-
Notifications
You must be signed in to change notification settings - Fork 10.2k
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
<base href="/" /> or base-tag alternative for Blazor MVC integration. #43191
Comments
@Varin6 thanks for contacting us. I think there might be some issues in your configuration or I am missing something. The initializers are fetched relative to the document. Here is where we load them. If you are serving your app from There are also features in routing that give you more flexibility in how/when you can map the path of the Blazor hub. |
@Varin6 thanks for the additional details. Here are some thoughts: There are two types of links that you can have in a document:
Blazor applications, like other types of applications (angular, react, vue, and any other SPA framework) rely on the document base to resolve document relative links. This is not a SPA specific decission, but a fundamental building block of how the web works. Offering a separate concept would mean that we would need to replicate the browser behaviors in every situation where the document base is used, and there would be cases in which we could not even make this work. Concretely, this affects:
This makes it very expensive/complex if not straight impossible to control everywhere, and as new functionality is added to the web, we are in a never ending catch-up race. With that in mind, the way to think about it is as follows. There are three sources of links in your page:
If you are rendering a Blazor application from different documents ( There are two approaches you can follow for this:
The first option is more complicated and is not likely what you are looking for as it would make navigations different on each document. For example, if you were to have a page For the second option, you would set the Some servers have the concept of app.Map("/base/path/", subapp => {
// You might need to use subapp.UsePathBase("/base/path/"); here
subapp.UseRouting();
subapp.UseEndpoints(endpoints => endpoints.MapBlazorHub());
}) An alternative is to pass a path to endpoints.MapBlazorHub("base/path"); The benefit of doing it this way is that you can map patterns, like In addition to that, if this is a Blazor webassembly application, you need to adjust the path of Finally, in the case of webassembly, you need to make sure that the files are in the correct location on disk. For that you need to make sure that Coming back to the first option, where you map the files dynamically, routing offers With all this said, the best way to go about this is:
There are some subset of things that I think we might be willing to entertain:
However, this will likely mean that document relative navigations in your app will not work correctly as they are dependent on the base path of the document. We are definitely not willing to reinvent the |
Thank you very much for this very descriptive reply. I digested it, looked again at my code and I have to come back to you with apologies. It turns out there was an obscure JS hidden in the dungeon of a code, which was rewriting anchors. Base-tag introduction affected the results of that code, as it affected the basepath that JS uses to rewrite URL in the browser, which meant that suddenly when trying to navigate to anchors produced a wrong URL in the browser. Any other JS that rewrites URLs might be affected. Before posting here, I tested it on another codebase to make sure it's not an isolated issue, turns out that other project I used to test it was based on our "base" code which contains that JS. Either way - it is still an "issue" when integrating Blazor into existing MVC, as the introduction of base-tag can affect the operation of the existing project in ways hard to predict. I can also see how this can just be labeled as "existing code issue" and nothing to do with Blazor config itself. I now have removed the code I posted above:
<script src="~/_framework/blazor.server.js" autostart="false"></script>
<script>
Blazor.start({
configureSignalR: function (builder) {
builder.withUrl("/_blazor", {
});
}
});
</script> and this hack in var rewriteOptions = new RewriteOptions();
rewriteOptions.AddRewrite("_blazor/initializers", "/_blazor/initializers", skipRemainingRules: true);
app.UseRewriter(rewriteOptions); and I have added base-tag, and all works fine after I rewrote the JS that was the culprit. Nevertheless, the hack above works, I am not knowledgeable enough to know whether it literally does what base-tag would do or whether it can yield unexpected issues. It worked flawlessly in my case until I figured the base-tag issue out. Thank you again for your informative reply, I have learned new things. |
@Varin6 no problem, this topic is complicated, it has come up several times and was due a more detailed write up that explained how things worked and why they work in that way. We might do some work in .NET 8.0 to make some of these scenarios easier. |
Thank you for the info. If you are interested what was causing the issue, this is the bit of code that rewrites url in the browser and allows to navigate to specific bootstrap tabs and open them when the address is entered in the URL bar: /*------------------------
* Location Hash Reload
* -----------------------*/
function locationHashReload() {
// show active tab on reload
if (location.hash !== '') {
let $target = $('a[href="' + location.hash + '"]');
if ($target.length) {
$target.tab('show');
}
}
// remember the hash in the URL without jumping
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
if (history.pushState) {
history.pushState(null, null, '#' + $(e.target).attr('href').substr(1));
} else {
location.hash = '#' + $(e.target).attr('href').substr(1);
}
// Fix scrollable datatables
$.fn.dataTable.tables({visible: true, api: true}).columns.adjust();
});
} This line: history.pushState(null, null, '#' + $(e.target).attr('href').substr(1));
var baseUrl = location.protocol + '//' + location.host + location.pathname; and change those two lines: history.pushState(null, null, baseUrl + '#' + $(e.target).attr('href').substr(1));
location.hash = baseUrl +'#' + $(e.target).attr('href').substr(1); This is probably an issue for those niche cases of established MVCs that have some JS scripts that use |
I have a similar question as to how the base path should be setup when a blazor server app is served via an iframe. I currently have a need to serve up my blazor server application via an iframe in a legacy webforms application(s). When the blazor app is loaded in the iframe the base path is relative to the site that is hosting the iframe, not relative to the blazor server app running in the iframe. What modifications or adjustments should I make to the blazor server app in order for the js and css to be loaded relative to the actual blazor server app? |
@javiercn can you please list the actionable items for us and what you think about those being in .NET 8 or backlog ? |
If anybody has this issue, here is my hack: // HACK: blazor server js hard code some path, making it works only on root path. This fix it.
// Workaround this bug https://github.com/dotnet/aspnetcore/issues/43191
var rewriteOptions = new RewriteOptions();
rewriteOptions.AddRewrite("_blazor/(negotiate|initializers|disconnect)$", "/_blazor/$1", skipRemainingRules: true);
rewriteOptions.AddRewrite("_blazor$", "/_blazor", skipRemainingRules: true);
app.UseRewriter(rewriteOptions); This rewrite the paths used by I also had to register static files manually due to a bug #19578 // HACK: Make blazor js available on: ~/_blazorfiles/_framework/blazor.server.js
// Workaround this bug https://github.com/dotnet/aspnetcore/issues/19578
app.UseStaticFiles(new StaticFileOptions()
{
RequestPath = "/_blazorfiles",
FileProvider = new ManifestEmbeddedFileProvider(typeof(ComponentServiceCollectionExtensions).Assembly),
OnPrepareResponse = LongCache
}); With private static void LongCache(Microsoft.AspNetCore.StaticFiles.StaticFileResponseContext ctx)
{
// Cache static assets for one year, set asp-append-version="true" on references to update on change.
// https://andrewlock.net/adding-cache-control-headers-to-static-files-in-asp-net-core/
const int durationInSeconds = 60 * 60 * 24 * 365;
ctx.Context.Response.Headers[HeaderNames.CacheControl] = "public,max-age=" + durationInSeconds;
} With this I can just to Integrating blazor server to existing project hasn't been smooth experience for now. |
To learn more about what this message means, what to expect next, and how this issue will be handled you can read our Triage Process document. |
#30316 is also related. |
To learn more about what this message means, what to expect next, and how this issue will be handled you can read our Triage Process document. |
One possible solution (discussed during triage) would be to emit a comment with the base path when debugging and log a warning if we detect that it was misconfigured. |
Thank you for this great explanation, it explains everything very clearly. But one big problem remains: Is there any way (without specifying it in the code or elsewhere) that a Blazor Server App can be installed anywhere? Never made a problem in the good old days of ASP and ASP.NET, should be solvable for Blazor as well. Thanks for any advice that helps to be flexible here. |
I followed this guide to add a Blazor control to an existing web app: This broke a lot of functionality in the MVC app, including logging out and sorting of data grids. I'd chosen to use a Blazor component in this way because it was going to save me a lot of time over writing the functionality in Javascript, and Microsoft said it was possible. Microsoft really need to make it clear in their documentation if doing something like this will break key functionality. My question has to be why when using a single component on it's own a base path should have to be specified. Surely it should only be necessary when using the routing functionality of Blazor. I couldn't get any of the workarounds above to work. Probably because I'm using a newer version. The following seems to work though for me. My workaroundIn layout.cshtml remove
and update
to
Add to program.cs
|
Is there an existing issue for this?
Is your feature request related to a problem? Please describe the problem.
Issue related to those issues, yet I think since those were reported, this is still a problem for a lot of programmers.
#14246
#24631
I am integrating a few components into an existing, large, multitenant MVC application - .NET6.
Applications frontend is views/partial views, I am injecting the Blazor components using
and everything works fine as long as it's on the main page. As soon as I try adding components anywhere else, the
_blazor/initializers
can't be found as blazor.js tries to look for them in the current path rather than the base path of the app.Adding
<base href="/" />
fixes this issue, but then it ruins a lot of other things in the existing MVC app, including any anchor tabs/bootstrap tabs, if the blazor component exists on that view.The choice I have right now is to either find an alternative for a base-tag or somehow fix the issues caused by the base-tag in the massive MVC app. From a business perspective, we wouldn't want to put so much work because base-tag is mandatory and there are no other ways of making it work. I feel like the integration side of Blazor is bit neglected, and businesses often first try new technology they want to implement before they decide to write an app fully using it. This stops the propagation of this tech.
Describe the solution you'd like
Currently I solved it (so far no errors in the console and everything works fine) with those two additions to my code:
In
_Layout.cshtml
I disable the autostart and add this config:This doesn't seems to solve the
_blazor/initializers
path so inProgram.cs
I had to add a rewrite:This works so far, not sure if I will need to add more rewrites when some other errors appear, I can't seem to find any more information about how to solve it, while finding a lot of topics about this same issue I am currently having, all related to integration of Blazor into existing MVC projects.
It could simply be just an elegant solution of passing one parameter as an option, for those cases where base-tag is not desired.
Additional context
No response
The text was updated successfully, but these errors were encountered: