How to make your frontend point to different backends?
by Mauricio Rojas, on Nov 5, 2019 10:21:57 AM
Once you have modernized your legacy VB6, Powerbuilder or Windows Forms App using WebMAP, your application is now a modern web application with an Angular Front End and ASP NET Core BackEnd. By default the code generated during a WebMAP migration is supposed to have both frontend and backend published on the same server. But suppose that you want to be able to have scenarios where you have your frontend in one location and your backend on another. Is that possible? Why will you want something like that? Well the answer for the latter is material for another post. But the answer for the first one is what I will try to explain in this post.
Ok. Sure it is possible to have your Angular application pointing to a backend on different locations. In order to do that, you have to do some modifications on your back-end code and your front-end code. So let's get it on:
The first thing you need to do is enable CORS.
Cross-origin resource sharing (CORS) is a mechanism that allows restricted resources on a web page to be requested from another domain outside the domain from which the first resource was served
To enable CORS follow these steps:
- On the
Startup.cs
modify ConfigureServices: If you just want to do a test you can usebuilder.AllowAnyOrigin()
However the right way to do it is to add the list of sites. For example for frontend1.company.com and frontend2.company.com you will do something like:
public void ConfigureServices(IServiceCollection services) { services.AddCors(options => options.AddPolicy('CORSSettings', builder => { builder.WithOrigins("http://frontend1.company.com") .WithOrigins("http://frontend2.company.com") .AllowAnyHeader() .AllowCredentials() }); });
Notice that you should add the AddCors line before the AddMVC. Also pay attention to the name you used for AddPolicy. For example here we are using the CORSSettings name for the policy.
- Go to ConfigureServices and add:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseCors("CORSSettings");
Remember that your should add the UseCors line before the UseMVC.
You should also remove the app.UseAntiforgeryToken();
because it is not compatible with CORS.
And those are all the changes for the backend.
Now we need to do something to redirect all our requests to a different URL.
The first thing is how to specify the URL. For now I will use environments
. Angular provides a mechanism called environments
. In general this is just a set of files you will find under src\enviroments
. This allows you to have a set of settings for lets say development and production. I will not go into detail on that. I will just assume you have all your different environments settings there, and that your environments have a baseURL
value. For example:
// The file contents for the current environment will overwrite these during build.
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
// The list of which env maps to which file can be found in `.angular-cli.json`.
export const environment = {
baseUrl : "http://localhost:8787",
production: false
};
Now, to redirect all requests we will create our custom HttpClient
. Lets add it under src\app
and save it in ApiHttpClient.ts
import { Injectable } from "@angular/core";
import { HttpHandler, HttpClient } from "@angular/common/http";
import { Observable } from "rxjs";
// Environment will be used to get settings
import { environment } from '../environments/environment';
@Injectable()
export class ApiHttpClient extends HttpClient {
public baseUrl: string;
public constructor(handler: HttpHandler) {
super(handler);
// Get base url from wherever you like, or provision ApiHttpClient in your AppComponent or some other high level
// component and set the baseUrl there.
this.baseUrl = environment.baseUrl;
}
private fixURL(url:string) : string {
if (url[0] == '/')
{
url = this.baseUrl + url;
}
else {
url = this.baseUrl + '/' + url;
}
return url;
}
public get(url: string, options?: Object): Observable<any> {
(<any>options).withCredentials = true;
return super.get(this.fixURL(url), options);
}
public post(url: string, body:any, options?: Object): Observable<any> {
// we need to always set the withCredentials to
// force sending cookies.
(<any>options).withCredentials = true;
return super.post(this.fixURL(url), body, options);
}
}
Don't despair, we are almost ready. We now have to make sure that our custom HttpClient
will be injected. So we need to inject it into our application module. Let's modify the file `src\app\app.module.ts'
import { NgModule, CUSTOM_ELEMENTS_SCHEMA, NgZone, ChangeDetectorRef} from '@angular/core';
import { AppComponent } from './app.component';
import { WebMapKendoModule } from '@mobilize/winforms-components';
import { WebMapService, WebMapModule } from '@mobilize/angularclient';
import { SKSModule } from './sks.module';
import { HttpClientModule, HttpClient, HTTP_INTERCEPTORS } from '@angular/common/http';
import { ApiHttpClient } from './ApiHttpClient';
@NgModule({
declarations: [
AppComponent,
],
imports: [
HttpClientModule,
BrowserModule,
WebMapKendoModule,
WebMapModule,
SKSModule,
],
providers: [WebMapService, { provide: HttpClient, useClass: ApiHttpClient} ],
bootstrap: [AppComponent],
schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
})
export class AppModule { }
And that's all.
With those changes you can now start playing around with all the different combinations of frontend and backend location.