Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RazorComponentResult returned component cannot execute clientside code #50762

Closed
michaelongithub opened this issue Sep 17, 2023 · 22 comments
Closed
Labels
area-blazor Includes: Blazor, Razor Components enhancement This issue represents an ask for new feature or an enhancement to an existing one feature-full-stack-web-ui Full stack web UI with Blazor ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. Pillar: Complete Blazor Web Status: Resolved

Comments

@michaelongithub
Copy link

michaelongithub commented Sep 17, 2023

Hi
I want to return a Razor Component from a controller. (.net 8 RC1, newest Blazor WebApp Template)

        public IResult CRT()
        {
            return new  RazorComponentResult<Components.Components.Counter>();
        }

I have a simple test component (the infamous Counter.razor) with @Attribute [RenderModeServer]
Returns correct rendered component But counter event is not triggered:

  • Not available for components returned with RazorComponentResult? Mere HTML rendering as standard Blazor 8 SSR ?
  • Will be available in RC2 / RTM
  • if not, how to have a MVC Architecture with clientside code for Blazor 8 ?

BTW: The same behaviour if I use the component inside a Razor page (cshtml) with @await Component.InvokeAsync("Counter");
So has this maybe to do with that these calls cannot handle the new @Attribute [RenderModeServer] ?

Thanks for information, Michael

@dotnet-issue-labeler dotnet-issue-labeler bot added the area-blazor Includes: Blazor, Razor Components label Sep 17, 2023
@marinasundstrom
Copy link

marinasundstrom commented Sep 17, 2023

You can't serve an interactive component without a static page in which to host it. That is why the new SSR model requires you to have the root App.razor (equivalent to index.html). It has to do with the Blazor JS script having to load once.

And I'm not sure that interactive components are supported for component endpoints anyway.

But theoretically:

To enable interactivity, you need to serve the blazor.web.js script, from the _framework path, and there is no easy way to expose that file without activating the entire thing by automatically mapping the components.

But you could check the source code, and look for the extension method with code that adds those static files to be hosted. I think it is in MapRazorComponents.

@michaelongithub
Copy link
Author

Hi
thanks for reacting so quickly.
in .net 7 going via an enveloping .cshtml and having a layout file used in that view with <script src="_framework/blazor.server.js"></script> and
@(await Html.RenderComponentAsync<BlazorWebAppVS1782Empty.Components.Components.Counter>(RenderMode.Server))
works with events. Haven't found out jet, how to make this work in .net 8 RC1. But expect that to work again analogously somehow latest at RTM. Is not as ideal as it would be directy via RazorComponentResult.
My main motivation for that was to be able to have an MVC pattern style architecture again for may Blazor apps.

@marinasundstrom
Copy link

@michaelongithub I see. You try to create an MVC style app with Razor Components for views in custom endpoints.

I don't think that it is a supported case. Component endpoints are not meant to allow you do create MVC-style apps like with "Razor Views" in MVC.

Btw. Another thing to consider is the use of layouts for shared UI. They will not work unless you have the Router and the RouteView. Because the latter applies that layout.

I do however agree that there are some things with component endpoints that aren't clear.

@michaelongithub
Copy link
Author

michaelongithub commented Sep 19, 2023

@marinasundstrom Thanks again. So my understanding of the current situation is as follows:

  • In its current inception for my motivation I don't see much use cases for RazorComponentResult. While I understand your initial explanations for the limitation I wonder what the use case intentions of the Blazor team are with this method.
  • Using Blazor Components with clientside code inside a Razor View was working in .net 7. I hope this will be available in .net 8 again or example / doc how this is working already with the new per component rendering mode.
  • I still would like to have the option of organizing Blazor apps with an MVC pattern architecture. Anybody know how to to that in .net 8 ? (Without taking recourse to the "clumsy" detour with embedding components in razor views which I assume will be working again)

@marinasundstrom
Copy link

marinasundstrom commented Sep 19, 2023

@michaelongithub Btw. I now see that you are using Component.InvokeAsync. Isn't that just for Razor View components? (Not Razor/Blazor components)

https://learn.microsoft.com/en-us/aspnet/core/mvc/views/view-components?view=aspnetcore-7.0

Have you tried using the component tag helper to render a Blazor component in a Razor View?

https://learn.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/built-in/component-tag-helper?view=aspnetcore-7.0

@marinasundstrom
Copy link

marinasundstrom commented Sep 19, 2023

@danroth27 Are interactive components supported through Minimal API endpoints returning ComponentResult?

(Apart from the limitation that you would have to render them in a SSR component)

@michaelongithub
Copy link
Author

michaelongithub commented Sep 19, 2023

@marinasundstrom Thanks again for the hint
I had already tried
@(await Html.RenderComponentAsync<BlazorWebAppVS1782Empty.Components.Components.Counter>(RenderMode.Server))

And now per your advice

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<component type="typeof(Counter)" render-mode="Server" />

both render but make no clientside code running.

@marinasundstrom
Copy link

marinasundstrom commented Sep 19, 2023

@michaelongithub

Have you included the script? (Provided that you run .NET 8)

<script src="_framework/blazor.web.js" suppress-error="BL9992"></script>

I checked, and the Blazor Server template uses:

 <script src="_framework/blazor.server.js"></script>

That is required to activate the interactivity. So it should be either directly in your view (.cshtml), or in a layout/master file.

@marinasundstrom
Copy link

marinasundstrom commented Sep 19, 2023

@michaelongithub I have created a functioning MVC app that has a view that renders an interactive Razor component. To me it seem like it is working in .NET 8.

https://github.com/marinasundstrom/BlazorMvcViewTest

The route is /Test.

Edit:

I also tested creating a component endpoint. /Test/foo that maps to the MyPage component which declares a Counter that has been marked as having RenderModeServer.

It is all using the normal Blazor Server stuff.

@michaelongithub
Copy link
Author

@marinasundstrom Tested Your Example:

  • Yes clientside code works
  • is as .net 8 Framework solution on the level of the project
  • but as far as I can see is still the .net 7 template with old _hosts and app.razor file
  • and uses .net 7 <script src="_framework/blazor.server.js"></script> and not <script src="_framework/blazor.web.js"></script> for .net 8.
  • But thanks anyway.

@marinasundstrom
Copy link

marinasundstrom commented Sep 20, 2023

@michaelongithub Yes. I created a Blazor Server .NET 7 project, and upgraded it. And true, I did not use the new script.

In the case of the TestController and its action and endpoint, I am not using _Host.cshtml at all. They are separate Razor views and Components. And the Razor view is just for demonstrating that you can embedd an interactive Razor component.

The issue is that Blazor only exposes blazor.web.js when invoking the MapRazorComponents<TRootComponent>. You only need to invoke those methods when you are using the stuff related to the integration with the router.

And I reckon that Blazor Server stuff is doing similar stuff as those extension methods under the hood.

Because the script is not being exposed, I asked @danroth27 for answers whether interactive components are supported in components from plain endpoints.

I have update the test app, and added a custom UseBlazorWebJS() method that maps the blazor.web.js file. It is based on this.

That way you can reference and use the newer script. But you will not be able to use Blazor WASM components without adding them to the container first - I think.

@SteveSandersonMS Perhaps you know the details of this? How to approach this scenario.

@mkArtakMSFT mkArtakMSFT added the enhancement This issue represents an ask for new feature or an enhancement to an existing one label Sep 20, 2023
@mkArtakMSFT mkArtakMSFT added this to the .NET 9 Planning milestone Sep 20, 2023
@ghost
Copy link

ghost commented Sep 20, 2023

Thanks for contacting us.

We're moving this issue to the .NET 9 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s).
If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues.
To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

@mkArtakMSFT mkArtakMSFT added the feature-full-stack-web-ui Full stack web UI with Blazor label Sep 20, 2023
@marinasundstrom
Copy link

marinasundstrom commented Sep 21, 2023

I have tested Minimal API endpoint with interactive components. It works.

https://github.com/marinasundstrom/BlazorMinimalApiTest

Created components:

  • Counter - Interactive on the server.
  • MyPage - equivalent to an index.html page (Server-side-rendered)

Register Razor component services:

builder.Services.AddRazorComponents()
    .AddServerComponents();

Serve the Blazor JS script:

app.UseBlazorWebJS()

Map endpoint:

app.MapGet("/test", () => new RazorComponentResult<BlazorMinimalApi.Components.MyPage>());

Map Blazor Hub:

app.MapBlazorHub();

I don't know how well this is documented. But then, the script is not exposed other than through the offical API.

@michaelongithub
Copy link
Author

@marinasundstrom Amazing. Admirable. Shows that it is basically possible in .net 8.

  • This is a minimal API scenario and built through the webapi template, not the cli dotnet new blazor (Blazor WebApp template in VS). I would have liked to have the team provide example / guidance / doc for an example based on that template with a programmatically returned Blazor component with clientside code. But maybe their moving the initial issue to Net 9 Planning means that it is not yet part of .net 8. ?
  • How did you go about /what was your reasoning to find out about UseBlazorWebJS? Is this part of the official Blazor 8 RC ?
  • Really don't want to keep you busy, not as tireless as you seem to be.

@marinasundstrom
Copy link

@michaelongithub I'm just a humble enthusiast and developer who is happy to help. And it was much needed distraction to me! 🙂

I guess it is about priorities. Now when the final release is near.

When I started experimenting with this, a month ago, I noticed that the blazor.web.js wasn't served unless you called MapRazorComponents(). So I dug into the code and extracted that bit into my own extension method.

The key to make interactive server components work is the .MapBlazorHub(), as well as serving the script.

I think that the Blazor team needs time to think about how to design these APIs.

In the meantime, you have this workaround. Which I documented about in my repository for others to see.

But I have not tried out WebAssembly. I guess that I need to expose more static files. I will update once I have explored that.

@michaelongithub
Copy link
Author

@marinasundstrom Thanks for letting me know. Currently we have not used and short term foreseeably don't intent to use WASM. So I will wait and see, what the team will come up with in RC2 and RTM. I hope they will clarify and document the state of affairs with regard the topics we discussed and You researched. And your distraction from whatever was at any rate very helpful for me, to see what the current state is with regard to my initial motivation.

@marinasundstrom
Copy link

marinasundstrom commented Sep 21, 2023

FYI. I got WebAssembly working as well. So added endpoint for that.

https://github.com/marinasundstrom/BlazorMinimalApiTest/blob/main/README.md

@michaelongithub
Copy link
Author

michaelongithub commented Sep 21, 2023

@marinasundstrom Indefatigable ! From the viewpoint of a wide perspective of a "Blazor Fullstack" I would expect the possibility to return a fully functional Blazor Component programmatically in a very straightforward way. My main argument being: You can return Razor Views and Pages (from Controllers). So please make that possible for Blazor Components. For me personally the primary concern is not minimal API's but a mvc application architecture.

@marinasundstrom
Copy link

marinasundstrom commented Sep 21, 2023

@michaelongithub You have to know that endpoints that serve Razor Components aren't a replacement for Razor Views in MVC. You will not get the same with Razor components.

You won't get things like layouts since they require you to have a Router component, and a RouteView component that applies the layout.

And I don't know if enhanced navigation, and such will work in your MVC case.

So in normal cases, when you are building full on interactive Blazor apps, you would rather use the other way of letting ASP.NET Core registering the pages to be used by the router.

But I think that since ASP.NET now supports rendering Blazor components through endpoints, and that you can add interactivity, then the functionality should be exposed so that developers can use it.

@marinasundstrom
Copy link

@mkArtakMSFT What should we do with this?

@javiercn
Copy link
Member

javiercn commented Oct 5, 2023

I am going to clarify the state of things for .NET 8.0

  • RazorComponentResult is designed to emit static HTML. There is no oficially supported way of achieving interactivity, although its technically possible to do so in several ways.

    • The reality is that when you try to do this at a "large scale", there are several things that you need to align to make things work (scripts, "special" framework endpoints, etc).
  • If you want to enjoy all the available features, (enhanced navigation, streaming rendering, auto mode, etc.) you need to use Blazor Web.

  • You can continue to use an MVC architecture with components via the component HTML helper or the tag helper. That will continue to work for the foreseable future, and its a perfectly valid alternative to have an island architecture.

    • The main missing features here are enhanced navigation, streaming rendering, and auto mode.

With this in mind, very likely our focus moving forward will be to continue expanding on the Blazor Web experience (MapRazorComponents), as that is the mainline scenario for us.

@michaelongithub
Copy link
Author

@javiercn: Thanks a lot for this clarification

@mkArtakMSFT mkArtakMSFT removed this from the .NET 9 Planning milestone Nov 5, 2023
@mkArtakMSFT mkArtakMSFT added this to the BlazorPlanning milestone Nov 5, 2023
@mkArtakMSFT mkArtakMSFT closed this as not planned Won't fix, can't repro, duplicate, stale Dec 20, 2023
@mkArtakMSFT mkArtakMSFT added the ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. label Dec 20, 2023
@ghost ghost added the Status: Resolved label Dec 20, 2023
@ghost ghost locked as resolved and limited conversation to collaborators Feb 7, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-blazor Includes: Blazor, Razor Components enhancement This issue represents an ask for new feature or an enhancement to an existing one feature-full-stack-web-ui Full stack web UI with Blazor ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. Pillar: Complete Blazor Web Status: Resolved
Projects
None yet
Development

No branches or pull requests

4 participants