I have a fully operative Blazor server-side project and a .NET Core 3 MVC project, both in the same solution. I'm now trying to use the components from the Blazor project in my MVC project.
I've managed to get the components to render on an MVC page, but button clicks on the Blazor component don't trigger the onclick events for the components, instead I just get navigated to https://localhost:44341/?
I'm unclear as to exactly what changes I need to make in the MVC solution to get this working? The official documentation talks about using components in and MVC project and it's mentioned in this video chat with Dan Roth, but neither go into the detail of how to achieve it.
Could anyone walk me though the full steps on how to retrofit server-side Blazor into an MVC project (or point me at an example)?
My Blazor project still has the standard template's Counter component, so I've tried to add that to my MVC solution by referencing the Blazor project and then adding this to my index.cshtml file:
<div id="Counter">
@(await Html.RenderComponentAsync<Counter>())
</div>
That renders correctly but the button clicks don't work.
I've added the JS file to MVC apps _Layout page:
<script src="_framework/blazor.server.js"></script>
Turned on Server Side Blazor in the MVC project's Startup.cs file:
services.AddServerSideBlazor();
I've also added Pages and Shared directories to the MVC project and copied over the _Imports and MainLayout files - not sure if that's needed.
When that didn't do it, I tried spinning up new projects from all the Blazor templates (client, client-hosted and server-side) to look for clues, but all of those examples are set up as complete SPAs with a single Blazor entry point (the App
file) hosted in a .html file, whereas I want to render Blazor components on lots of different existing MVC pages.
I then experimented with adding parts of those projects (and parts of my working Blazor project) into the MVC project, but can't get it to work fully.
I tried following the answer here too, but that's working with adding the Blazor component files into the MVC project, whereas my Blazor files are currently (mostly) in a different project.
services.AddServerSideBlazor();
in the MVC app's Startup.cs. is anything else needed there?AspNetCore.Routing
, do I still need to switch to Core 3's endpoint routing if I'm only placing the components on existing MVC pages (I.e. I won't have Blazor pages, just Blazor components). <app>@(await Html.RenderComponentAsync<App>())</app>
line from _Host.cshtml somewhere in my MVC project?Blazor is an alternative to MVC and Razor Pages but with a twist: It's a single-page app framework (SPA) that just happens to use C# instead of JavaScript. Blazor applications can run on the server, or in the browser thanks to Web Assembly (https://www.telerik.com/blogs/goodbye-javascript-hello-webassembly).
Razor components can be integrated into Razor Pages and MVC apps in a hosted Blazor WebAssembly solution.
I've got to the bottom of this now. After all the trial and error described in my question the solution turns out to involve surprisingly little code.
The answer below assumes you have a working server-side Blazor project in your solution and are trying to use components from that project in a separate MVC project in that same solution. I did this in VS2019, using Core 3 Preview 5.
See the bottom of the page or a link to an example of MVC and Blazor in the same project.
You just need to add a reference to your blazor project:
<ProjectReference Include="..\MyClient.Web.Blazor\MyClient.Web.Blazor.csproj" />
Add the base url into the head:
<head>
<meta charset="utf-8" />
<base href="~/" />
Add a reference to the Blazor JS Script
<script src="_framework/blazor.server.js"></script>
(This doesn't actually exist on your local file system, Blazor automagically sorts it out by the time the app gets to the browser)
This is where the real work is done
In the ConfigureServices
method add:
services.AddServerSideBlazor();
I then switched my configuration over to the new style Core 3 configuration (so no longer using the AddMvc
method):
services.AddControllersWithViews()
.AddNewtonsoftJson(options =>
{
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
});
services.AddRazorPages();
And then the change that finally got it all working for me was to switch to Core 3's endpoint routing in the Configure(IApplicationBuilder app, IWebHostEnvironment env)
method:
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
endpoints.MapBlazorHub();
});
//app.UseMvc(routes =>
//{
// routes.MapRoute(
// name: "MyArea",
// template: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
// routes.MapRoute(
// name: "default",
// template: "{controller=Home}/{action=Index}/{id?}");
//});
The commented out code shows the old style routing I was using. I think it was the absence of endpoints.MapBlazorHub();
that was causing my button click issue
No changes were needed to the Blazor project to get this working.
Once you've done all of the above, all that's needed to get your component to render on an MVC page is to add
@(await Html.RenderComponentAsync<YourComponent>())
That should work on both an MVC page and a Razor page.
The above changes were all that I needed to make to get it working. There is a known issue with Core 5 where once you navigate to an MVC or Razor page with a Blazor component on it, the routing will no longer work until the page is refreshed - the URLs will change in the browser's address bar, but no navigation will occur.
I'm now running on Preview 6 and I can confirm the routing issue is now fixed from Preview 6 onward.
Chris Sainty has an example of server-side Blazor components added in to an existing MVC project here: Using Blazor Components In An Existing MVC Application (source here)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With