Public Apps & Custom UIs
The Public Apps functionality in ArconQ allows developers to make their apps publicly available, exposing them to remote clients and interfaces. This functionality makes it possible to expose REST APIs for use by remote clients and allows the UI to be reachable via remote browsers.
Custom UIs on the other hand allows developers to tie their public app with related frontend, which can be either self-hosted or external.
How to register Public App
Apps that are made public are never available publicly directly. They can safely use tokens forwarded by the WebAppHost/AppProxy without calling the Identity Server. Only the claims, roles, and groups available in the token are used for authorization logic.
To add the Public Apps functionality to a client application, developers can use the following code in their app app.UsePublicApp(builder.Configuration)
var app = builder.Build();
// has to be called right after building our app object
app.UsePublicApp(builder.Configuration);
// rest of your invocations
app.UseArconQ();
app.MapArconQ();
await app.RunAsync();
Please note that order here is important. app.UsePublicApp() must be executed as the first invocation after building app object
and also before app.UseArconQ() and app.MapArconQ(). Otherwise, you can run into routing issues!
After this code is added, the app will be available under the following URL:
https://arconq.prod/apps/public/{appAlias}/{appApi}
/apps/public section of the URL is configurable in appSettings.
appAlias is Application Alias, it can be changed in Web UI
arconq.prod is a default domain of the ArconQ
Custom UIs
During registration of public app, there is a possibility of registering Custom UIs tied to the app. It can be done via extension method shown in a snippet below:
var app = builder.Build();
app.UsePublicApp(builder.Configuration)
.AddCustomUserInterface("Blazor", "/")
First argument of the method specifies name which will be displayed in Admin Console. Second one is the relative path pointing to frontend of the app.

Custom UIs can be hosted by app using ready-to-go .NET app templates or outside of app scope. Let's talk about both scenarios.
App-hosted Custom UIs (.NET)
Steps for using Custom UIs vary regarding framework of choice. Please, skip to section with your framework of choice not to waste precious time.
Given that app should be the host of your Custom UI, ArconQ supports Blazor Server, Angular and React.
Blazor Server
If you want to use Blazor Server just generate new Blazor Server project via command dotnet new blazorserver with your desired options.
Next step is to modify Program.cs file accordingly to snippet below:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureArconQ(builder.Configuration);
builder.Services.AddArconQ(builder.Configuration);
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
var app = builder.Build();
// Register app as public and provide CustomUserInterface
app.UsePublicApp(builder.Configuration)
.AddCustomUserInterface("{your custom UI display name}", "/");
app.UseArconQ();
app.MapArconQ();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
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.UseStaticFiles();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.Run();
Angular
If you want to use Angular just generate new Angular with ASP.NET Core project via command dotnet new angular with your desired options.
Next step is to modify Program.cs file accordingly to snippet below:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureArconQ(builder.Configuration);
builder.Services.AddArconQ(builder.Configuration);
// Add services to the container.
builder.Services.AddControllersWithViews();
var app = builder.Build();
// Register app as public and provide CustomUserInterface
app.UsePublicApp(builder.Configuration)
.AddCustomUserInterface("{your custom UI display name}", "/");
app.UseArconQ();
app.MapArconQ();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
// 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.UseStaticFiles();
app.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
app.MapFallbackToFile("index.html"); ;
app.Run();
Next step is to go ClientApp/src folder and modify index.html by setting empty href on base HTML tag.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>PublicAppAngular</title>
<!-- href value has to be empty string! -->
<base href="" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
</head>
<body>
<app-root>Loading...</app-root>
</body>
</html>
Last step requires changing getBaseUrl() function in main.ts file to return URL in format {yourdomain}/apps/public/{appAlias}/.
Snippet below is using localhost as the domain.
App alias must match while creating new app instance in admin console. It has to be exactly the same.
import { enableProdMode } from "@angular/core";
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
import { AppModule } from "./app/app.module";
import { environment } from "./environments/environment";
export function getBaseUrl() {
return "https://arconq.prod/apps/public/public-app-angular/";
}
const providers = [{ provide: "BASE_URL", useFactory: getBaseUrl, deps: [] }];
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic(providers)
.bootstrapModule(AppModule)
.catch((err) => console.log(err));
React
If you want to use React just generate new React with ASP.NET Core project via command dotnet new react with your desired options.
Next step is to modify Program.cs file accordingly to snippet below:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.WebHost.ConfigureArconQ(builder.Configuration);
builder.Services.AddArconQ(builder.Configuration);
builder.Services.AddControllersWithViews();
var app = builder.Build();
// Register app as public and provide CustomUserInterface
app.UsePublicApp(builder.Configuration)
.AddCustomUserInterface("{your custom UI display name}", "/");
app.UseArconQ();
app.MapArconQ();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
// 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.UseStaticFiles();
app.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
app.MapFallbackToFile("index.html"); ;
app.Run();
Next step is to go to ClientApp folder and open package.json file. Under "name" property you have to add "homepage" property with the value {yourdomain}/apps/public/{appAlias}.
Snippet below is using localhost as the domain.
App alias must match while creating new app instance in admin console. It has to be exactly the same.
"name": "publicappreact",
// homepage field has to be added here!
"homepage": "https://arconq.prod/apps/public/public-app-react",
"version": "0.1.0",
"private": true,
...
Externally hosted Custom UIs
Custom UIs can also be hosted outside of the app. Given that URL to Custom UI has to be relative we need to create the controller which will be responsible for redirecting our calls to addresses where our frontend is available.
[Route("[controller]")]
[ApiController]
public class UIController : ControllerBase
{
[HttpGet("angular")]
public RedirectResult GetAngularAppRedirect()
{
//under relative url of ui/angular we return redirect to address of frontend app
return new RedirectResult("http://localhost:4201");
}
[HttpGet("react")]
public RedirectResult GetReactAppRedirect()
{
return new RedirectResult("http://localhost:4203");
}
[HttpGet("blazor")]
public RedirectResult GetBlazorAppRedirect()
{
return new RedirectResult("http://localhost:4202");
}
}
To make them available in Admin Console the only thing left to be done is registration of those apps in Program.cs file:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.WebHost.ConfigureArconQ(builder.Configuration);
builder.Services.AddArconQ(builder.Configuration);
builder.Services.AddScheduledJob<WeldingProcessReporter>().WithIntervalSchedule(5, IntervalType.Seconds);
var app = builder.Build();
app.UsePublicApp(builder.Configuration)
.AddCustomUserInterface("Angular", "/ui/angular")
.AddCustomUserInterface("React", "/ui/react")
.AddCustomUserInterface("Blazor", "/ui/blazor");
app.UseCors(x =>
{
x.AllowAnyOrigin();
});
app.MapControllers();
app.UseArconQ();
app.MapArconQ();
await app.RunAsync();
Above scenario and registrations results in having 3 Custom UIs tied to our app as you can see below:

While writing your user interfaces be aware of the URL of public app while making calls to your app - it has to be an exact match. Otherwise all app API calls will result in 404 Not Found Status.
Security Considerations
When making apps publicly available, it's important to consider the security implications. For example, exposing an API publicly may open it up to potential attacks and vulnerabilities. Additionally, allowing external access to the UI may make it more difficult to control access and maintain security.
To mitigate these risks, it's important to follow best practices for secure coding and architecture. This may include implementing authentication and authorization mechanisms, using encryption and secure communication protocols, and implementing security testing and monitoring.
Conclusion
The Public Apps functionality in ArconQ provides a powerful tool for developers to make their apps available to external clients and interfaces. By following best practices for secure coding and architecture, it's possible to ensure that these apps are accessible while maintaining the highest levels of security.