Support PathBase deployments under subfolders
This commit is contained in:
@@ -77,6 +77,7 @@ VS Code F5 debug profiles are available in `.vscode/launch.json`:
|
|||||||
- `RpgRoller: Server + Firefox (F5)`
|
- `RpgRoller: Server + Firefox (F5)`
|
||||||
|
|
||||||
To use a custom SQLite database path, set `ConnectionStrings__RpgRoller`.
|
To use a custom SQLite database path, set `ConnectionStrings__RpgRoller`.
|
||||||
|
To run under a subfolder (for example `/rpgroller`), set `PathBase` (for example `PathBase=/rpgroller`).
|
||||||
|
|
||||||
For migration authoring, use the local tool command form:
|
For migration authoring, use the local tool command form:
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
<base href="/"/>
|
<base href="@BaseHref"/>
|
||||||
<title>RpgRoller</title>
|
<title>RpgRoller</title>
|
||||||
<link rel="stylesheet" href="/styles.css"/>
|
<link rel="stylesheet" href="styles.css"/>
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Baloo+2:wght@400;500;600;700&family=Nunito:wght@400;600;700&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Baloo+2:wght@400;500;600;700&family=Nunito:wght@400;600;700&display=swap" rel="stylesheet">
|
||||||
@@ -16,7 +16,24 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<Routes @rendermode="InteractiveServer"/>
|
<Routes @rendermode="InteractiveServer"/>
|
||||||
<script src="/js/rpgroller-api.js"></script>
|
<script src="js/rpgroller-api.js"></script>
|
||||||
<script src="_framework/blazor.web.js"></script>
|
<script src="_framework/blazor.web.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[CascadingParameter]
|
||||||
|
private Microsoft.AspNetCore.Http.HttpContext? HttpContext { get; set; }
|
||||||
|
|
||||||
|
private string BaseHref
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var pathBase = HttpContext?.Request.PathBase.Value;
|
||||||
|
if (string.IsNullOrWhiteSpace(pathBase))
|
||||||
|
return "/";
|
||||||
|
|
||||||
|
return pathBase.EndsWith('/') ? pathBase : $"{pathBase}/";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,6 +10,18 @@ builder.Services.AddScoped<RpgRollerApiClient>();
|
|||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
app.InitializeRpgRollerState();
|
app.InitializeRpgRollerState();
|
||||||
|
|
||||||
|
var configuredPathBase = builder.Configuration["PathBase"];
|
||||||
|
if (!string.IsNullOrWhiteSpace(configuredPathBase))
|
||||||
|
{
|
||||||
|
var normalizedPathBase = configuredPathBase.Trim();
|
||||||
|
if (!normalizedPathBase.StartsWith('/'))
|
||||||
|
normalizedPathBase = $"/{normalizedPathBase}";
|
||||||
|
|
||||||
|
normalizedPathBase = normalizedPathBase.TrimEnd('/');
|
||||||
|
if (normalizedPathBase.Length > 0)
|
||||||
|
app.UsePathBase(normalizedPathBase);
|
||||||
|
}
|
||||||
|
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
app.UseAntiforgery();
|
app.UseAntiforgery();
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,19 @@ window.rpgRollerApi = (() => {
|
|||||||
stopped: true
|
stopped: true
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function toAppUrl(url) {
|
||||||
|
if (!url || typeof url !== "string") {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(url)) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
const relativeUrl = url.startsWith("/") ? url.slice(1) : url;
|
||||||
|
return new URL(relativeUrl, document.baseURI).toString();
|
||||||
|
}
|
||||||
|
|
||||||
function clearReconnectTimer() {
|
function clearReconnectTimer() {
|
||||||
if (stateStream.reconnectTimer) {
|
if (stateStream.reconnectTimer) {
|
||||||
clearTimeout(stateStream.reconnectTimer);
|
clearTimeout(stateStream.reconnectTimer);
|
||||||
@@ -50,7 +63,7 @@ window.rpgRollerApi = (() => {
|
|||||||
clearReconnectTimer();
|
clearReconnectTimer();
|
||||||
invokeDotNet("OnConnectionStateChanged", "reconnecting");
|
invokeDotNet("OnConnectionStateChanged", "reconnecting");
|
||||||
|
|
||||||
const source = new EventSource(`/api/events/state?campaignId=${encodeURIComponent(stateStream.campaignId)}`);
|
const source = new EventSource(toAppUrl(`api/events/state?campaignId=${encodeURIComponent(stateStream.campaignId)}`));
|
||||||
stateStream.source = source;
|
stateStream.source = source;
|
||||||
|
|
||||||
source.onopen = () => {
|
source.onopen = () => {
|
||||||
@@ -122,7 +135,7 @@ window.rpgRollerApi = (() => {
|
|||||||
|
|
||||||
let response;
|
let response;
|
||||||
try {
|
try {
|
||||||
response = await fetch(url, options);
|
response = await fetch(toAppUrl(url), options);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return {
|
||||||
ok: false,
|
ok: false,
|
||||||
|
|||||||
Reference in New Issue
Block a user