Megabit/Blazorise

JSInterop Exception using Tooltip in v0.9.5

mikeu opened this issue · 14 comments

mikeu commented

Describe the bug
When using the Tooltip component on v0.9.5, an error is thrown in the console and the Blazor Server application crashes:

Loading module from “https://localhost:5001/_content/Blazorise/tooltip.js” was blocked because of a disallowed MIME type (“”).
Error: Microsoft.JSInterop.JSException: error loading dynamically imported module
   at async ValueTask<TValue> Microsoft.JSInterop.JSRuntime.InvokeAsync<TValue>(long targetInstanceId, string identifier, object[] args)
   at async ValueTask Blazorise.Modules.JSTooltipModule.Initialize(ElementReference elementRef, string elementId, object options)
   at async void Blazorise.Tooltip.OnInitialized()+(?) => { }
   at async Task Blazorise.BaseAfterRenderComponent.OnAfterRenderAsync(bool firstRender)
   at async Task Blazorise.BaseComponent.OnAfterRenderAsync(bool firstRender)
   at async Task Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle)

I have tried in current versions of both Firefox and Chrome, with both Blazorise.Bootstrap and Blazorise.Material. All combinations work under v0.9.4.8 (and earlier), and throw an error under v0.9.5.

To Reproduce
Steps to reproduce the behaviour:

  1. Have a project using the <Tooltip> component working correctly under v0.9.4.8 (possibly not in the root path, see below).
  2. Upgrade the appropriate Blazorise package (e.g. Blazorise.Bootstrap) to v0.9.5.
  3. Start the project and navigate to a page showing the tooltip.
  4. See the error in the console.
  5. Downgrade to v0.9.4.8, it starts working again.

Expected behaviour
The tooltip should display in the browser without throwing any error or severing the websocket connection to Blazor Server.

Additional context
I don't know whether this is relevant, but my Blazor Server application resides in a subdirectory. There is an ASP.NET API served on https://localhost:5001 and handled by controllers, while Blazor is running on https://localhost:5001/admin.

This setup has been working perfectly with previous versions of Blazorise, but I mention it because the invalid MIME type error displayed immediately before the exception does not include that custom path. That is, it fails to load https://localhost:5001/_content/Blazorise/tooltip.js, which makes sense, because the file is at https://localhost:5001/admin/_content/Blazorise/tooltip.js. Although I'm not sure why the error is that the module has an invalid MIME type, instead of that it doesn't exist...

Can you tell us how did you set up your app to be behind a subdirectory?

mikeu commented

For sure, the main idea is to use MapWhen on the IApplicationBuilder in my startup configuration to use the Blazor hub and pages when the request path starts with the subdirectory, and to use the API controller endpoints otherwise.

Specifically, in my Startup.Configure method with injected parameter IApplicationBuilder app, I use something like:

app.MapWhen(context => context.Request.Path.StartsWithSegments("/admin"), admin =>
{
    admin.UsePathBase("/admin");
    admin.UseStaticFiles();
    admin.UseRouting();
    admin.UseEndpoints(endpoints =>
    {
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToPage("/Admin/_Host");
    });
});
app.MapWhen(context => !context.Request.Path.StartsWithSegments("/admin"), api =>
{
    api.UseRouting();
    api.UseAuthentication();
    api.UseAuthorization();
    api.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller}/{action=Index}/{id?}"
        );
    });
});

Then my Blazor pages (*.razor along with _Host.cshtml) live in <Project root>/Pages/Admin.

My guess is that perhaps something in v0.9.5 is not respecting the call to UsePathBase, though I haven't had any chance at all to look into it more deeply than that yet. Hopefully that's enough to help sort out the issue as my repo is unfortunately an internal project, but I could try to put together a public repo that demonstrates the issue if required. Let me know!

A small public repo to reproduce the issue would be great. In the meantime, we will try with the code sample that you posted.

I have applied the route changes and it seems to be working without any issues on my side. Is there any chance you're behind a firewall?

mikeu commented

I do have both a hardware and a software firewall between me and the internet at large, but I'm running everything locally and encountering this error on localhost within Visual Studio. My application has been working correctly for months under earlier versions, and the only thing required to break/fix it is to upgrade/downgrade the single Blazorise nuget package.

Here is a project that's reproducing the issue (on my computer, at least!): https://github.com/mikeu/blazorise-3122-repro. Hopefully it either also reproduces it for you, or gives a clue as to what I need to change to keep working with the latest version of Blazorise. Assuming that you see the error when you visit the subdirectory page, you should then also be able to downgrade Blazorise and see the tooltip appear without error. Please let me know if there's anything else I can do to help resolve this.

Hello,
Here's our release notes for 0.9.5
https://blazorise.com/news/release-notes/095

We've moved to using Javascript modules, which means we do all the heavy lifting behind the scenes, and you may remove the calls to blazorise.js and other resources (see docs, migration point 7)
image

We've assumed the default convention / location to map your static files. Meaning we'll try to grab them out of /_content/Blazorise/tooltip.js
In your configuration you are mapping the static files under
subdir/_content/Blazorise/tooltip.js
and blazorise does not know how to figure out this.
EDIT: We actually grab from the relative path, which is correct, see next comment. :)

@stsrki I guess we can take a look at enabling blazorise configuration so that a relative path to the static assets can be given?

@mikeu in the meantime, you can just make sure to map the static files at the root, by calling app.UseStaticFiles(); before having your vpath configured programatically as currently blazorise expects them to be served there. Is this okay?

@stsrki actually I was taking a further look at this as I was considering already submitting a PR with a new BlazoriseOptions property named StaticFilesPath, and I noticed the relative path is already well considered by Blazorise.

Just that we have some hardcoded paths on our js for code reuse.
Can you take a look?
image

image

mikeu commented

Hi @David-Moreira , thanks for that link. I did look for migration details yesterday, but between the docs page's not working properly and not having the release notes on the main project readme, I didn't find that info. I'm not sure it's related to the problem, as the behaviour seems to be basically the same with or without those files referenced in _Host.cshtml, but definitely good to know!

As for calling app.UseStaticFiles() as well as subdir.useStaticFiles(), that does seem to solve the crash. It doesn't feel quite ideal to pollute the API routes with static files for the sub-page, but I don't think it's really a problem either; I wasn't planning to have a /_content endpoint. So I'm definitely happy to move forward with that for now at least, though perhaps in a future version we'll be able to configure the base path via the BlazoriseOptions in services.AddBlazorise(), as you suggest.

One interesting point is that the network tab shows first a request for https://localhost:5001/status/_content/Blazorise.Bootstrap/tooltip.js?v=0.9.5.0 (note the correct, expected /subdir segment!), followed immediately by one for https://localhost:5001/_content/Blazorise/tooltip.js (no version parameter, and no /subdir). So even though the Blazorise package isn't able to figure out that the files are under subdir, the Blazorise.Bootstrap package is, somehow.

mikeu commented

Hah, looks as if we noticed that path in Blazorise.Bootstrap at just about the same time! Thanks for looking into this as well :)

@David-Moreira I don't think adding a static path to the configuration would be needed. Based on the .NET and Blazor documentation the path should be solved by the framework. We did all "by the book", and every path starts with "./_content/" which gets picked by the framework. If we would add the static path to the config that would make it hard to import modules from javascript. Remember, we also import tooltip.js in Blazorise.Bootstrap project from JS.

I think app.UseStaticFiles() is the best and only solution to this. And seems to work just fine. If this happens to repeat we can report it on the AspNetCore repo and see what they got to say.

Can you take a look at my comment :

Just that we have some hardcoded paths on our js for code reuse.
Can you take a look?

That to me isn't by the book as it does not take into account the relative path like in the other places, it's hard coded to the root instead. So we have two different behaviours.

Edit: my initial suggestion was because I tought we had a hardcosed path, but I noticed we actually resolve a relative path on the c# side. On js it's hard coded to root.

@David-Moreira You might be right. When I was first implementing JS Modules and trying to do the import of the root tooltip.js from Blazorise.Bootstrap:

import { initialize as baseInitialize, destroy, updateContent } from "/_content/Blazorise/tooltip.js";

it didn't work when I added ./_content. Only with the /_content was working for me.


Now, I'm trying to come up with a better way and it seems that the following works just fine.

import { initialize as baseInitialize, destroy, updateContent } from "../Blazorise/tooltip.js";

Which makes sense. Blazorise DLL would always be loaded first and we just need to go up one directory to get to its static files.

Based on my testing now, it works in all scenarios, With or without a virtual subdirectory path.

I will submit a PR and you can test on your side.

I'm getting the same or similar problem using version 0.9.5.

GET https://[servername]/_content/Blazorise/tooltip.js net::ERR_ABORTED 404

Notice that it's missing the directory before _content. I only noticed it when I deployed to a server. But it works locally. I think it's because locally it's using localhost so there is no subdirectory.

So was this presumably fixed?

@stevenlupo Yes, it is fixed but we didn't release an update yet. We need to finish some other issues before.