using Microsoft.Extensions.FileProviders;
using NewLife;
using NewLife.Cube.Extensions;
namespace Rainbow.Web;
/// <summary>Rainbow 服务注册与中间件扩展方法</summary>
/// <remarks>
/// 独立部署时:
/// services.AddRainbow()
/// app.UseRainbow()
/// </remarks>
public static class RainbowExtensions
{
#region 服务注册
/// <summary>注册 Rainbow 所需的额外服务(当前为空壳,预留扩展点)</summary>
/// <param name="services">服务集合</param>
/// <returns></returns>
public static IServiceCollection AddRainbow(this IServiceCollection services)
{
// 预留:未来可在此注册 Rainbow 特有的服务
return services;
}
#endregion
#region 中间件配置
/// <summary>配置 Rainbow 中间件:嵌入静态资源(React SPA 前端)与 SPA 路由回退</summary>
/// <param name="app">应用构建器</param>
/// <returns></returns>
public static WebApplication UseRainbow(this WebApplication app)
{
var env = app.Environment;
var assembly = typeof(RainbowExtensions).Assembly;
var embeddedProvider = new CubeEmbeddedFileProvider(assembly, "Rainbow.Web.wwwroot");
if (!String.IsNullOrEmpty(env.WebRootPath) && Directory.Exists(env.WebRootPath) && env.WebRootFileProvider != null)
{
// 磁盘 wwwroot 优先,再到嵌入资源作为后备;确保 pnpm build 后的新前端文件能立即生效
env.WebRootFileProvider = new CompositeFileProvider(
env.WebRootFileProvider,
embeddedProvider);
}
else
{
env.WebRootFileProvider = embeddedProvider;
}
app.UseStaticFiles();
// 仅对已知前端路由做 SPA 兜底,不干扰静态文件、API(/api/*)和 Cube 后台(/admin/*)
app.MapFallbackToFile("/devices/{**path}", "index.html");
app.MapFallbackToFile("/wan/{**path}", "index.html");
app.MapFallbackToFile("/firewall/{**path}", "index.html");
app.MapFallbackToFile("/pppoe/{**path}", "index.html");
app.MapFallbackToFile("/dhcp/{**path}", "index.html");
app.MapFallbackToFile("/dns/{**path}", "index.html");
app.MapFallbackToFile("/settings/{**path}", "index.html");
app.MapFallbackToFile("/members/{**path}", "index.html");
app.MapFallbackToFile("/stats/{**path}", "index.html");
// 根路径兜底(仪表盘首页)
app.MapFallbackToFile("index.html");
return app;
}
#endregion
}
|