Add AsyncComponentRenderer - fixes #23#30
Conversation
|
Thanks for the PR.. just looking at this to see what it does and how it works. There are no tests and no examples of usage, so I can't accept the PR into the main app for those reasons. However, it does give me a point to try to integrate into the existing code. Ideally what we need is a method on |
|
I understand you'd prefer to add the method to the existing class, but from what I understand its code is based on bUnit so it has a bunch of stuff you don't actually need if you only want to get the HTML. I didn't see a way to add RenderAsync to it while keeping the implementation as simple as it is now so I made a separate class. Example usage: var parameters = new Dictionary<string, object>()
{
{ nameof(MyComponent.Model), new Model() { Value = "Test" } },
{ nameof(MyComponent.Title), "Test" },
};
var renderer = new AsyncComponentRenderer<MyComponent>(serviceProvider, loggerFactory);
var html = await renderer.RenderAsync(parameters);Note that I'm not sure you can use nameof() directly on the component, in my own code I have the component implement an interface. I can add tests as well, just wanna make sure you approve of the usage/API first. |
|
I have pushed some changes since there were some issues with the initial implementation. |
|
Hello! I was working on the same thing, and then I've noticed that there was already a PR for the same topic. I will look with more attention but from a first look it seems that the synchronization is made with a newly introduced semaphore. |
|
I tried a couple of use cases, and noticed that RenderRootComponentAsync requires an async lock (SemaphoreSlim). If you always create a new renderer for one render, then you don't need it of course, but I wanted to support every use case I could think of. This library was based on a unit testing library, and in ContainerComponent.cs I read: // This also avoids the use of Renderer's RenderRootComponentAsync APIs, which are
// not a good entrypoint for unit tests, because their asynchrony is all about waiting
// for quiescence. We don't want that in tests because we want to assert about all
// possible states, including loading states.A lot of the code in this library is to support the unit testing use case. A use case that doesn't apply to this library. And this comment tells us that we can instead use the built-in RenderRootComponentAsync. So that's what I did. You mentioned that "NextRender" already exists. This also seems like an artifact from being based on a unit testing library, and I feel like your solution won't work if you put multiple delays in OnInitializedAsync (you may need to manually call StateHasChanged, but I suspect if you tried to make a test for this it wouldn't work). So my solution may look complicated but I think that's just because I use a different API so there's more change, while your solution integrates better with the existing code. |
|
Yep, NextRender appear to be marked as completed (and then substitued with a new task) each time an update on the page is triggered. I also agree that this code derives from a testing library and I've also tryed to use the RenderRootComponentAsync method too (i've noticed the same comment), but as you said it required a lot of changes in the code. That other solution (PR #33 ) have a very low impact and integrates well with already tested features. About my solution, given the place where i've awaited NextRender it is waits until the OnInitializeAsync is completed, no mater how many delay I await inside it, looks like that also the other async lifecycle methods are respected as well but i've not tested them explicitly. I'll do other test in the next days to see if there are any edge cases. Anyway, which are the other scenario your solution can cover? other than that, how can you know for sure when the page have finished grabbing things? maybe i'm thinking just to email and report generation, and you need to use it in scenario when there is user interaction and take snapshots? |
|
Seems like this library will become obsolete in .NET 8 |
|
Yes, I think that will be the case, although I'll leave it alone for anyone using .NET Core 3.x - 7 as they will be able to use it. |
Basically a copy of Htmlizer.cs, using Renderer.RenderRootComponentAsync() to properly await any async work being done in components.