ASP.NET serving angular app and deployUrl is deprecated - asp.net

I have an ASP.NET app (.NET 6.0), and I have a route /ngxapp which serves my angular 13 app. The angular app is copied to wwwroot/ngxapp folder (see below how it's built).
I've been using this .NET code for years to deliver angular app:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
// this is for reverse proxy (NGINX)
app.UseForwardedHeaders(new()
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
}
app.UseHttpsRedirection();
// this must be before the next (angular) section, otherwise 404's are not handled
app.UseStatusCodePagesWithReExecute($"{ANGULAR_APP_ROUTE_S}/404");
app.Use(async (context, next) =>
{
RewriteXFrameOptionsHeader(context);
await next();
RedirectEmptyRootToAngularApp(context, ANGULAR_APP_ROUTE_S);
await RewriteAssets(context, next);
await RedirectForAngular(context, next, ANGULAR_APP_ROUTE_S);
});
app.UseDefaultFiles(new DefaultFilesOptions {DefaultFileNames = new List<string> {"index.html"}});
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapRazorPages();
});
It allows to open angular app even when user requests for some non-root angular route (for example, https://<domain>.com/ngxapp/someroute-1/subroute/etc). Basically, everything works like a charm.
Now, when I build an angular app I've always used --deploy-url=/ngxapp/ param, like so (from windows batch .cmd file):
call ng build --base-href /%folder% --deploy-url /%folder%/ --configuration=production
The latest version of angular compiler shows me the warning about deployUrl:
Option "deployUrl" is deprecated: Use "baseHref" option, "APP_BASE_HREF" DI token or a combination of both instead. For more information, see https://angular.io/guide/deployment#the-deploy-url.
I read the docs on APP_BASE_HREF and built angular app without --deploy-url parameter. Also, used APP_BASE_HREF:
#NgModule({
declarations: [AppComponent, CreateUrlComponent, NotAuthorizedComponent, FormFocusDirective],
imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
...
],
providers: [
{ provide: APP_BASE_HREF, useValue: environment.baseHref }, // baseHref = "/ngxapp"
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
],
bootstrap: [AppComponent]
})
export class AppModule {
constructor() {}
}
But now, when I run ASP.NET app with the angular app in place (opening https://localhost/ngxapp in the browser), the requests of all .js files are empty and their MIME type is text/html. Basically, they're not found.
If I return back to using deploy-url parameter in the angular build, everything works!
What am I missing here?
Comes down to this
When --deploy-url is used, the request Url is correct:
https://localhost:44389/ngxapp/filename.js
because the script block contains correct url's:
<script src="/ngxapp/runtime.js" type="module"></script>
When --deploy-url is not used, ngxapp part is missing:
https://localhost:44389/filename.js
and the script block is:
<script src="runtime.js" type="module"></script>

I made it work. Here's how I wanted the angular part to work within ASP.NET app:
if I have a special route for angular app called /ngxapp within my ASP.NET application, I want any link containing '/ngxapp' part to work seemlessly. For example, if a user paste https://example.com/ngxapp/child/subchild to a browser address, and the angular app does have child/subchild routes, then ASP.NET app should serve the https://example.com/ngxapp/index.html and the angular router takes over and serves child/subchild.
The problem is when ASP.NET serves angular's app index.html from /ngxapp, the script tags in the index file must have a valid path related to wwwroot/ngxapp/ folder (scr='/ngxapp/some-angular-file.js, and not just src='/some-angular-file.js'). This works when --deploy-url flag is used.
Now, when the flag is deprecated, I had to create a rewrite rule in ASP.NET which actually catches any file served from angular app folder and rewrites it to the correct path accordingly: from /whatever-angular-file.js to /ngxapp/whatever-angular-file.js.
With this custom URL rewriting rule in place, everything works as expected, and --deploy-url is not needed.

Related

Blazor handling asp pages

I have migrated old ASP pages (www.company.com/index.asp) to the Blazor project and I am trying to display "Not Found page" to the users accessing web site via "old bookmarks" like www.company.com/contact.asp.
I have tried in the _host.cshtml redirection, but condition is never met.
#if ((Request.Path.ToString()?.Contains(".asp")).GetValueOrDefault())
{
LocalRedirect("/NotFound");
return;
}
I have tried to add #page directive #page "/{oldPage}.asp" to NotFound blazor component, but application does not render any page at all then.
I would rather solve *asp handling in the application itself rather than on the IIS or proxy, because I do not have direct access to proxy/IIS settings.
Is there any hint how to solve this ?
The solution is to add to Startup.cs endpoints.MapGet("/{page}.asp", async x => { x.Response.Redirect("/NotFound"); });
Full snippet:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
endpoints.MapGet("/{page}.asp", async x => { x.Response.Redirect("/NotFound"); });
});

Hangfire Dashboard broken after deployment - not load css and js

when working the development the dashboard is seen correctly, but when it is uploaded to production not load the css and js files
project version net core 3.1 api
hangfire error
my startup
app.UseHangfireDashboard("/hangfire", new DashboardOptions
{
Authorization = new[] { new CustomAuthorizationFilter() }
});
I tried the following without results, the server is windows and the authorization filter is simple... I'm not sure what the problem is... but it doesn't load the css and js files
app.Use((context, next) =>
{
// note : comment this to debug locally
context.Request.PathBase = "jobs";
return next();
});

Nextjs module federation with standalone servers

I'm trying to use module federation (webpack 5) beetween nextjs applications.
I started from this example (two nextjs applications) and everything works as expected. From my point of view the problem is that this works only if i have both app on the same host.
The relevant webpack configuration part on next.config.js is below (the same in the other app)
....
remotes: {
next1: isServer
? path.resolve(
__dirname,
"../next1/.next/server/static/runtime/remoteEntry.js"
)
: "next1",
},
...
If i just remove the server configuration it doesn't works.
It is possible to use module federation between nextjs app without configure the remote server by folder path and reference the remote app only by url ?
It is possible, but it won't work with SSR. Just leave the remote with the global for client side:
// next.config.js
....
remotes: {
next1: "next1",
},
...
Create your component and import the remote:
// component.js
const Component = (await import("next1/component")).default
export default Component
And finally in your page, lazy load your remote component with SSR disabled:
// mypage.js
import dynamic from 'next/dynamic'
const RemoteComponent = dynamic(
() => import('../components/component.js'),
{ ssr: false }
)
const MyPage = () => (<RemoteComponent />)
export default MyPage
There's a working sample here: https://mf-shell.vercel.app/
And the code: https://github.com/schalela/mf-nextjs

Deployed to Azure: Fixing the Mime Type sends an empty css file to the server

Everything is working fine locally. But when deployed to Azure, loading the css shows this error:
Resource interpreted as Stylesheet but transferred with MIME type text/plain
It happens in all the browsers.
The application loads a spa in react.
These are the middlewares I am using in this order.
if (Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStatusCodePagesWithReExecute("/Home/Error", "?statusCode={0}");
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseOurCustomAuthenticate();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action}/{id?}");
routes.MapRoute(
name: "api",
template: "api/{controller}/{action}/{id?}");
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (Environment.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "start");
}
});
The custom authenticate middleware that we are using checks if the path starts with "/styles" it will not do anything and let it load.
This is the cshtml file where I include the css file:
<!DOCTYPE HTML>
<html>
<head>
<link rel="stylesheet" type="text/css" href="~/styles/notFound.css">
</head>
<body class="body-content">
This is where the styles and images are
The image is being loaded properly on the server, only the style have this problem.
So in my custom middleware I did this:
if (httpContext.Request.Path.StartsWithSegments("/styles"))
{
httpContext.Response.ContentType = "text/css";
}
Now the content-type is correct in the network tab, but the style is not still loading. When I click on the css file it is an empty file.
I have read a lot of posts regarding this issue, but couldn't still solve it.
At this point I had to see if the stylesheet is actually deployed.
To do so, I pulled the contianer and run it locally to see what files are copied there.
I found that the styleSheet is copied under a folder "Styles" with capital "S" instead of "styles" with small "s". We use git for our source control and git didn't catch the rename I made to this folder.
This is how to commit such a change with git case sensitive. Renaming the folder properly fixed the problem for me.

Adding Facebook login to Angular2-Meteor app

I am attempting to add Facebook authentication into an Angular2-Meteor app that started off as the Socially app from the tutorial and is slowly being modified into something less generic. There doesn't seem to be much posted on this particular use case however.
Note: I've asked in the Meteor forums and Gitter without success already.
Here are the steps I've taken:
Added Service Configuration package using
meteor add service-configuration
Created a file at server/services.ts containing (with my actual keys):
ServiceConfiguration.configurations.upsert({
"service": "facebook"
}, {
$set: {
"settings": {
"appId": “appid”,
“secret": "secret",
"loginStyle": "popup"
}
}
});
But on compile, I get an error saying
cannot find name 'ServiceConfiguration'
Which makes me think the package didn't install properly, but uninstalling/reinstalling it has not resolved the issue and it is showing in my .meteor directory.
Client side I'm calling this method with a click event on a button in a component that does have Meteor imported:
facebook() {
Meteor.loginWithFacebook((err) => {
if (err) {
//Handle error
} else {
//Handle sign in (I reroute)
this.router.navigate(['/home']);
}
})
Which throws the console error
meteor_1.Meteor.loginWithFacebook is not a function
But I suspect this is secondary to the fact that ServicesConfiguration isn't registering.
Git repo of the project is here: https://github.com/nanomoffet/ng2-starter with the referenced files being server/services.ts and client/app.ts
Currently it is not possible to use the ServiceConfiguration in TypeScript. What I did in my application was that I created a Javascript file in which I did make the ServiceConfiguration calls.
meteor add service-configuration
Create the file ./server/service-config.js
Meteor.startup(() => {
ServiceConfiguration.configurations.remove({
service: "facebook"
});
ServiceConfiguration.configurations.insert({
service: "facebook",
appId: '<APP_ID_YOU_GET_FROM FROM_FACEBOOK>',
loginStyle: "popup",
secret: '<SECRET_YOU_GET_FROM_FACEBOOK>'
});
});
I only tested it with Google and works fine for me.

Resources