Preamble
In our current setup, I am developing a class library that acts as a plugin to our platform. This "works" because the executable scans its own directory and automatically loads every assembly that follows the naming pattern plugin_<assembly_name>.dll. When such an assembly is loaded, the executable looks for any class implementing a specific interface and calls the StartService() method on it.
What am I trying to do?
One of our requirements is to have a form of configuration for the end-user. We want to achieve this by having the internal Service start a Kestrel thread and serve a basic Blazor app that allows the user to log in with a username and password, and then set some values which are being stored and passed around in the platform through event-handling.
What works
The implementation actually works in a sense that I am able to spin up my Kestrel server and serve the Blazor content that I have written. To achieve this, I have created a WebServer class in C# that uses the WebApplication and WebApplicationBuilder classes to construct and configure the entire Kestrel server, enable Blazor, and use the DI container to inject all services and dependencies.
internal class WebServer : IDisposable
{
private Task? _applicationThread;
private readonly ILogger _logger = logger;
private readonly CancellationTokenSource _cancellationTokenSource = new();
public void Start()
{
var token = _cancellationTokenSource.Token;
_logger.LogInformation("Starting web server");
var application = BuildWebApplication();
application.UseStaticFiles();
application.UseRouting();
application.UseAuthorization();
application.MapRazorComponents<App>().AddInteractiveServerRenderMode();
application.UseAntiforgery();
_applicationThread = Task.Run(async () => await application.StartAsync(token), token);
}
}
There's more to the above code, but I hope it gets the idea across.
What's the problem?
When I access the application on localhost, I can actually get the embedded server to handle the request. But all components handled through MudBlazor are not working because the embedded resources from that nuget package are not accessible:
[2025-11-06T14:42:06.438Z] Error: Microsoft.JSInterop.JSException: Could not find 'mudElementRef.getBoundingClientRect' ('mudElementRef' was undefined).
I believe this is related because my wwwroot is not available to the class library (despite being part of the project).
I had to do the following for example in my App.razor to make the favicon work:
@using System.Reflection
@using Microsoft.AspNetCore.Components.Authorization
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="/" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
<link href="_content/MudBlazor/[email protected]" rel="stylesheet" />
<link rel="icon" type="image/png" href="@FaviconUrl" />
<HeadOutlet @rendermode="InteractiveServer" />
</head>
<body>
<CascadingAuthenticationState>
<Routes @rendermode="InteractiveServer"/>
</CascadingAuthenticationState>
<script src="_content/MudBlazor/[email protected]"></script>
<script src="_framework/blazor.web.js"></script>
</body>
</html>
@code {
private string FaviconUrl { get; set; } = string.Empty;
protected override void OnInitialized()
{
base.OnInitialized();
// This is workaround to load the favicon from embedded resources
using var imageStream = Assembly
.GetExecutingAssembly()
.GetManifestResourceStream("MyQ.PlugIn.GatewayConfigurationPlugin.wwwroot.favicon.png");
using var ms = new MemoryStream();
imageStream?.CopyTo(ms);
FaviconUrl = $"data:image/png;base64,{Convert.ToBase64String(ms.ToArray())}";
}
}
So my understanding is that the resources referenced for MudBlazor such as the _content/MudBlazor/MudBlazor.min.js are suffering from the same problem.
Am I missing some specific setting for Kestrel to tell it that
_contentneeds to point to embedded/nuget packages?Is what I am trying to achieve even doable?