How to change base url? - asp.net-core

I am not sure the title of the question is correct, but I'll try to explain what I need.
We host multiple web applications on a single machine, so
https://localhost:8080
and
https://localhost:8081
point to different applications.
Meanwhile, API gateway maps request without dropping the URL suffix:
https://api.domain.com/service1/Home/Index
turns into
https://localhost:8080/service1/Home/Index
and
https://api.domain.com/service2/Home/Index
into
https://localhost:8081/service2/Home/Index
I would like the app's root ~ to resolve to hostUrl+suffix where suffix is a configured value.
I used this blogpost to globally prefix all the routes for controllers and pages, but now I struggle with static files.
I am able to virtually move wwwroot:
app.UseStaticFiles(new StaticFileOptions
{
RequestPath = $"/{GlobalPrefix}"
});
but <link href="~/bootstrap/css/bootstrap.css" rel="stylesheet" /> does not contain GlobalPrefix part when rendered.
So I would like to add this GlobalPrefix to whatever base URL site is hosted at. Be it a self-hosted app or in IIS.
P.S. RTFM =)

Using app.UsePathBase("/myPath")(https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.builder.usepathbaseextensions.usepathbase?view=aspnetcore-2.2) is working in that case.
There have been changes in ASP.NET Core 2 regarding that (http://github.com/aspnet/Announcements/issues/226). Also, be aware of a strange behavior: http://github.com/aspnet/HttpAbstractions/issues/893

Related

app.MapFallbackToFile causes reload the entire SPA site if the URL typed manually

I use the latest recommended SPA + .Net Core-based Web APi pattern where the FE referenced to BE, FE serves proxy to BE during development, and app.UseDefaultFiles()serves index.html where the SPA resides during production. This pattern means no proxy middleware is required as it was in opposite direction when the BE serves FE as a proxy.
app.UseDefaultFiles(); <-- Here the site is loaded first time
app.UseStaticFiles();
app.MapControllers();
app.MapFallbackToFile("/index.html"); <-- Here the site is reloaded if URL typed(changed) manually
Client-side routing is the point. Specifically, I use Vue Router and IIS hosting. When the site is already opened, and a user types URL in the browser, it falls down to app.MapFallbackToFile("/index.html") and then Vue router handles the route.
The problem is that the site is always completely reloading when the URL is just changed (let say from mysite.com/a to mysite.com/b) in this scenario, as I would press F5. It's not always necessarily bad but I would like to control it.
The question is: how to get rid of app.MapFallbackToFile("/index.html") and somehow pass the captured URL to the SPA, as it would be naked SPA without backend which now stays in front of frontend.
If have tried Vue Spa with ASP.NET Core 6 minimal setup and it seems for me, that there is no way to achieve what you want.
When user enters or changes the URL address, the browser navigate away from the page and do a GET request to BE (Backend).
Here is the catch-all fallback route required, otherwise the user gets the 404 error from the web server.
I presume you use the HTML5 History Mode. Here is a part from the Vue Router Docs about this problem.
Since our app is a single page client side app, without a proper
server configuration, the users will get a 404 error if they access
https://example.com/user/id directly in their browser. Now that's
ugly.
Not to worry: To fix the issue, all you need to do is add a simple
catch-all fallback route to your server. If the URL doesn't match any
static assets, it should serve the same index.html page that your app
lives in. Beautiful, again!
If somebody yet knows the solution, please post a new answer.
It would be great to know how to do it!

Only Map existing Blazor Pages(Razor Components) in the pipeline?

The usual pattern for Blazor (server) apps, is that at the end pf program.cs there is app.MapFallbackToPage("/_Host");
That will result in ALL request paths, that match no earlier endpoint, executing the Blazor App. Sure the Blazor App has a <NotFound> Renderfragment, but that will still result in establishing the SignalR and so on. What if I want to display a static file (.html) from wwwroot or a specfic RAZOR PAGE (.cshtml), which doesnt establlish a websocket for all those cases where the route does NOT EXIST IN ANY BLAZOR PAGE ???
NavigationManager.NavigateTo cannot be used directly inside the BuildRenderTree markup of the <NotFound> ... I could maybe put a component inside there that redirects OnInitialized ... but that would still first require the SignalR.
How can I completely avoid Blazor/SignalR for URLs that don't exist in the Blazor App ?
Idea: I could try to add ALL POSSIBLE Blazor-routes as fallbacks and the most general fallback to some static file or Razor Page... but that seems LIKE A LOT OF DOUBLE WORK and very error prone... is there no way?
app.MapFallbackToPage("~/Admin/{*clientroutes:nonfile}", "/_Host");
app.MapFallbackToPage("~/SomeRoute/More/{*clientroutes:nonfile}", "/_Host");
app.MapFallbackToPage("~/SomePage/{*clientroutes:nonfile}", "/_Host");
app.MapFallbackToPage("/NotValidRoute");
Edit:
#Reason:
I wanted to have a single fallback page (razor page or static) for all routes/urls that don't match any target in the app. But sadly as it seems, that conflicts with blazor'S client side routing. since the server-side routing does not know, which routes should be handled by blazor, it also cannot know, which routes would not map to anything (razor pages and blazor combined). Other please correct me here.
There's server-side routing and client-side routing. On the server side, the middleware pipeline runs first, handling static files and server defined routes, including the fallback route. Fallback routes are routes that don't match static file requests and have the lowest priority, so they are not preferred over other matching routes.
Server-side routing has no idea what routes are going to match on the client-side. That data model is separate. What's happening is, when no server route matches, the host page is rendered, which bootstraps the client. Now you've transitioned to client-side routing and cannot re-enter (without a change to refresh the browser)
What if I want to display a static file (.html) from wwwroot or a specfic RAZOR PAGE (.cshtml), which doesnt establlish a websocket for all those cases where the route does NOT EXIST IN ANY BLAZOR PAGE ???
That requires knowing what routes exists on the client.
Idea: I could try to add ALL POSSIBLE Blazor-routes as fallbacks and the most general fallback to some static file or Razor Page... but that seems LIKE A LOT OF DOUBLE WORK and very error prone... is there no way?
Possible using the <NotFound> component to run some JavaScript and redirect the browser to a fixed route on the server.
Edit:
Another would be to build that found all routable razor components and map them all as fallback routes to "_Host".
Something like this (untested):
// This should match wherever components are declared.
var types = typeof(Program).Assembly.GetTypes();
foreach (var type in types)
{
if (typeof(ComponentBase).IsAssignableFrom(type) && type.GetCustomAttribute<RouteAttribute>() is { } routeAttribute)
{
var route = routeAttribute.Template;
endpointRouteBuilder.MapFallbackToPage(route, "/_Host");
}
}
It partly depends on how your app is hosted. In IIS, you can add applications to any website, which are basically websites of any type you want with a "/path" added.
Currently, my company's main app is "ABCsite.com," and my Blazor app is "ABCsite.com/Blazor"

JS storefront URL is picked up for OCC_BACKEND_BASE_URL_VALUE"

Running into very strange situation with the Spartacus setup on CCV2. After setting up the meta placeholder in the index.html file:
I setup the baseURL as null in environment.ts and environment.prod.ts, just to be double sure.
baseUrl: null,
It seems to work, but the problem is when storefront is deployed, JS store is picking up the JS storefront URL for content load
https://JS Storefront URL/XXXwebservices/v2/SITE/cms/pages
My understanding is that it should be ACC Storefront URL:
https://ACC Storefront URL/XXXwebservices/v2/SITE/cms/pages
Is there any other setting that needs to be made? Other than the ones identified above? do we need any other configuration on the CCV2 side of things?
The initial answer below didn't make too much sense, let me retry:
I recommend to leave out the baseUrl in the configuration completely, as the current behaviour prioritises the configuration over the meta-tag. See https://github.com/SAP/spartacus/issues/5886 for more info.
While the MEDIA_BACKEND_BASE_URL_VALUE has been added in Spartacus to distinguish the api and media, CCv2 has not yet implemented this feature. See also https://github.com/SAP/spartacus/issues/2212#issuecomment-490089609.
This is why the Spartacus side of it works, but the media base Url doesn't get injected on ccv2.

Blazor server side behind reverse proxy 404

I have a blazor server-side app hosted on IIS behind a reverse proxy (using ARR).
I have tried everything I can think of, but I keep getting 404 on
_framework/blazor.server.js
My base href is is set to "/subsite/":
<base href="/subsite/" />
and all my src values are relative like this:
<script src="_framework/blazor.server.js"></script>
<script src="_content/BlazorInputFile/inputfile.js"></script>
<script src="animations.js"></script>
Every other script ref loads fine, EVEN the _content data, but not the blazor.server.js.
I tried the old PathBase trick for MVC apps as well with no success:
if (!env.IsDevelopment()) {
app.Use((context, next) => {
context.Request.PathBase = new PathString("/subsite");
return next();
});
}
Can anyone tell me how to make Blazor realize where to put the blazor.server.js in a reverse proxy scenario?
Did you try the UsePathBase ?
app.UsePathBase("/subsite");
Here is my test result
Please check this article for more
https://www.billbogaiv.com/posts/net-core-hosted-on-subdirectories-in-nginx
From docs.
Rewrite URLs for correct routing
Routing requests for page components in a Blazor WebAssembly app isn't as straightforward as routing requests in a Blazor Server, hosted app. Consider a Blazor WebAssembly app with two components:
Main.razor – Loads at the root of the app and contains a link to the About component (href="About").
About.razor – About component.
When the app's default document is requested using the browser's address
bar (for example, https://www.contoso.com/):
The browser makes a request.
The default page is returned, which is usually index.html.
index.html bootstraps the app.
Blazor's router loads, and the Razor Main component is rendered.
In the Main page, selecting the link to the About component works on the client because the Blazor router stops the browser from making a request on the Internet to www.contoso.com for About and serves the rendered About component itself. All of the requests for internal endpoints within the Blazor WebAssembly app work the same way: Requests don't trigger browser-based requests to server-hosted resources on the Internet. The router handles the requests internally.
If a request is made using the browser's address bar for www.contoso.com/About, the request fails. No such resource exists on the app's Internet host, so a 404 - Not Found response is returned.
Because browsers make requests to Internet-based hosts for client-side pages, web servers and hosting services must rewrite all requests for resources not physically on the server to the index.html page. When index.html is returned, the app's Blazor router takes over and responds with the correct resource.
When deploying to an IIS server, you can use the URL Rewrite Module with the app's published web.config file. For more information, see the IIS section.
Maybe you could try to enable the forward proxy in IIS manager->server node->application request routing cache->proxy->enable.
If you only have one website, you could just add the website to ARR server farm and then it will create the routing rule automatically. It will be convenient to monitor the back-end server with health check.
Is this ARR warning causing my 404?

How to enable offline support when using HTML5 history api

What are the best practices (and how to go about doing it) to support offline mode when using html5 history api for url rewrites?
For example, (hypothetically) I have a PWA SPA application at https://abc.xyz which has internationalization built in. So when I visit this link, the Vue router (which ideally could be any framework - vue, react, angular etc.) redirect me to https://abc.xyz/en.
This works perfectly when I am online (ofcourse, the webserver is also handling this redirect so that app works even if you directly visit the said link).
However, its a different story when I am offline. The service worker caches all resources correctly so when I visit the URL https://abc.xyz everything loads up as expected. However, now if I manually type the URL to https://abc.xyz/en, the app fails to load up.
Any pointers on how to achieve this?
Link to same question in github: https://github.com/vuejs-templates/pwa/issues/188
Yes, this is possible quite trivially with Service Workers. All you have to do is to configure the navigateFallback property of sw-precache properly. It has to point to the cached asset you want the service worker to fetch if it encounters a cache miss.
In the template you posted, you should be good to go if you configure your SWPrecache Webpack Plugin as follows:
new SWPrecacheWebpackPlugin({
...
navigateFallback: '/index.html'
...
})
Again, it is absolutely mandatory that the thing you put inside navigateFallback is cached by the Service Worker already, otherwise this will fail silently.
You can verify if everything was configured correctly by checking two things in your webpack generated service-worker.js:
the precacheConfig Array contains ['/index.html', ...]
in the fetch interceptor of the service worker (at the bottom of the file), the variable navigateFallback is set to the value you configured
If your final App is hosted in a subdirectory, for example when hosting it on Github pages, you also have to configure the stripPrefix and replacePrefix Options correctly.