From e2b7374887f3ebe8f6824cbfeab84bed00b1bf8b Mon Sep 17 00:00:00 2001 From: trueai-org Date: Wed, 26 Jun 2024 12:30:15 +0800 Subject: [PATCH] feat: winform webapi --- MDriveSync.sln | 6 + src/MDriveSync.Client.API/Program.cs | 546 ++++++++++++++++----------- src/MDriveSync.Client.API/Startup.cs | 126 +++++++ 3 files changed, 459 insertions(+), 219 deletions(-) create mode 100644 src/MDriveSync.Client.API/Startup.cs diff --git a/MDriveSync.sln b/MDriveSync.sln index 4e92ae4..9e0047b 100644 --- a/MDriveSync.sln +++ b/MDriveSync.sln @@ -31,6 +31,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MDriveSync.Infrastructure", EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{3CE27DBE-FA45-41B6-A170-A721CD66562B}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MDriveSync.Client.WinFormAPI", "src\MDriveSync.Client.WinFormAPI\MDriveSync.Client.WinFormAPI.csproj", "{585E1ED7-B1D9-4EEE-AF65-32853A05FA9E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -61,6 +63,10 @@ Global {4D5DF593-BC91-4803-99AA-7872DFA98987}.Debug|Any CPU.Build.0 = Debug|Any CPU {4D5DF593-BC91-4803-99AA-7872DFA98987}.Release|Any CPU.ActiveCfg = Release|Any CPU {4D5DF593-BC91-4803-99AA-7872DFA98987}.Release|Any CPU.Build.0 = Release|Any CPU + {585E1ED7-B1D9-4EEE-AF65-32853A05FA9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {585E1ED7-B1D9-4EEE-AF65-32853A05FA9E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {585E1ED7-B1D9-4EEE-AF65-32853A05FA9E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {585E1ED7-B1D9-4EEE-AF65-32853A05FA9E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/MDriveSync.Client.API/Program.cs b/src/MDriveSync.Client.API/Program.cs index dcda7fd..27c7521 100644 --- a/src/MDriveSync.Client.API/Program.cs +++ b/src/MDriveSync.Client.API/Program.cs @@ -1,15 +1,8 @@ -using MDriveSync.Core; -using MDriveSync.Core.BaseAuth; -using MDriveSync.Core.Dashboard; -using MDriveSync.Core.Filters; -using MDriveSync.Core.Middlewares; using MDriveSync.Infrastructure; -using Microsoft.AspNetCore.Mvc; using Quartz.Logging; using Serilog; using Serilog.Debugging; using System.Diagnostics; -using System.Runtime.InteropServices; namespace MDriveSync.Client.API { @@ -17,44 +10,18 @@ public class Program { public static void Main(string[] args) { - var builder = WebApplication.CreateBuilder(args); - - var env = builder.Environment; - - //// 添加配置文件 - //var configuration = builder.Configuration - // .AddJsonFile($"appsettings.json", optional: true, reloadOnChange: true) - - // // 环境变量中的 - // .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true); - - // //// 加载默认的 - // //.AddJsonFile($"{ClientSettings.ClientSettingsPath}", optional: true, reloadOnChange: true); - - //// 添加自定义配置文件 - //builder.Configuration.AddJsonFile($"{ClientSettings.ClientSettingsPath}", optional: true, reloadOnChange: true); - - //// 当打包为单个 exe 程序时,使用代码显式配置 Serilog,而不是完全依赖于配置文件。 - //// 这可能导致 Serilog 在尝试自动发现和加载其扩展程序集(如 Sinks)时遇到问题 - //// 显式配置 Serilog:在程序的 Main 方法中,使用代码显式配置 Serilog,而不是完全依赖于配置文件。 - //// 即:要么手动列出 Sinks 或者通过下面这种方式 - //var logOptions = new ConfigurationReaderOptions( - // typeof(ConsoleLoggerConfigurationExtensions).Assembly); + var builder = CreateHostBuilder(args).Build(); + var env = builder.Services.GetService(); // 配置 Serilog var logger = new LoggerConfiguration() - .ReadFrom.Configuration(builder.Configuration); - - //// 打包为单个 exe 文件,无法写日志,因此在这里配置写死 - //.WriteTo.File("logs/log.txt", rollingInterval: RollingInterval.Day); + .ReadFrom.Configuration(builder.Services.GetService()); if (env.IsDevelopment()) { logger.MinimumLevel.Debug() .Enrich.FromLogContext(); - //.WriteTo.Console(); - // 使用 Serilog.Debugging.SelfLog.Enable(Console.Error) 来启用 Serilog 的自我诊断,这将帮助诊断配置问题。 SelfLog.Enable(Console.Error); } @@ -72,194 +39,17 @@ public static void Main(string[] args) { Log.Information($"Current: {Directory.GetCurrentDirectory()}"); - // 使用 Serilog - builder.Host.UseSerilog(); - - // 作业客户端配置 - builder.Services.Configure(builder.Configuration.GetSection("Client")); - - //// API 视图模型验证 400 错误处理 - //builder.Services.Configure(options => - //{ - // options.SuppressModelStateInvalidFilter = true; - //}); + //// 使用 Serilog + //builder.Host.UseSerilog(); - // API 异常过滤器 - // API 方法/模型过滤器 - builder.Services.AddControllers(options => - { - options.Filters.Add(); - options.Filters.Add(); - }); - - // 自定义配置 API 行为选项 - // 配置 api 视图模型验证 400 错误处理,需要在 AddControllers 之后配置 - builder.Services.Configure(options => - { - // 方法1:禁用 ModelState 自动 400 错误处理,使用自定义方法验证 - // 需要在控制器方法中手动调用 ModelState.IsValid,或者在控制器方法中使用 [ApiController] 特性,或者使用 ActionFilterAttribute 过滤器 - //options.SuppressModelStateInvalidFilter = true; - - // 方法2:自定义模型验证错误处理 - options.InvalidModelStateResponseFactory = (context) => - { - var error = context.ModelState.Values.FirstOrDefault()?.Errors?.FirstOrDefault()?.ErrorMessage ?? "参数异常"; - Log.Logger.Warning("参数异常 {@0} - {@1}", context.HttpContext?.Request?.GetUrl() ?? "", error); - return new JsonResult(Result.Fail(error)); - }; - }); - - // 后台服务 - //builder.Services.AddHostedService(); - - // 使用单例模式 - - // 阿里云盘后台服务 - builder.Services.AddSingleton(); - builder.Services.AddHostedService(provider => provider.GetRequiredService()); - - // 本地存储后台服务 - builder.Services.AddSingleton(); - builder.Services.AddHostedService(provider => provider.GetRequiredService()); - - var app = builder.Build(); - - //// 区分 API 和静态/客户端路由 - //app.Use(async (context, next) => - //{ - // if (context.Request.Path.StartsWithSegments("/api")) - // { - // // 如果是 API 请求,继续执行后续中间件 - // await next(); - // } - // //else - // //{ - // // app.MapFallbackToFile("index.html"); - - // // //// 非 API 请求,尝试作为静态文件处理 - // // //await next(); - - // // //// 不是 API 请求,重写请求到 index.html - // // //if (!Path.HasExtension(context.Request.Path.Value)) - // // //{ - // // // context.Request.Path = "/index.html"; - // // // await next(); - // // //} - // //} - //}); - - app.UseStaticFiles(); - - app.UseCors(builder => - { - builder.AllowAnyMethod().AllowAnyHeader().SetIsOriginAllowed(origin => true).AllowCredentials(); - }); - - // 添加基础认证 - // 从环境变量获取配置,如果 appsettings.json 中的配置为空 - var userFromConfig = builder.Configuration["BasicAuth:User"]; - var passwordFromConfig = builder.Configuration["BasicAuth:Password"]; - var user = string.IsNullOrEmpty(userFromConfig) ? - Environment.GetEnvironmentVariable("BASIC_AUTH_USER") : userFromConfig; - - var password = string.IsNullOrEmpty(passwordFromConfig) ? - Environment.GetEnvironmentVariable("BASIC_AUTH_PASSWORD") : passwordFromConfig; - - // 如果账号和密码 - if (!string.IsNullOrWhiteSpace(user) && !string.IsNullOrWhiteSpace(password)) - { - var basicAuth = new BasicAuthAuthorizationUser() - { - Login = user, - PasswordClear = password - }; - var filter = new BasicAuthAuthorizationFilterOptions - { - RequireSsl = false, - SslRedirect = false, - LoginCaseSensitive = true, - Users = new[] { basicAuth } - }; - var options = new DashboardOptions - { - Authorization = new[] { new BasicAuthAuthorizationFilter(filter) } - }; - - // 全局 - app.UseMiddleware(options); - - //// 部分 - //app.UseWhen(context => context.Request.Path.StartsWithSegments("/api"), appBuilder => - //{ - // appBuilder.UseMiddleware(options); - //}); - } - - // 从配置或环境变量中获取是否开启只读模式 - var isReadOnlyMode = builder.Configuration.GetSection("ReadOnly").Get(); - if (isReadOnlyMode != true) - { - if (bool.TryParse(Environment.GetEnvironmentVariable("READ_ONLY"), out var ro) && ro) - { - isReadOnlyMode = ro; - } - } - - if (isReadOnlyMode == true) - { - app.UseMiddleware(isReadOnlyMode); - } - - // 演示模式处理 - var isDemoMode = builder.Configuration.GetSection("Demo").Get(); - if (isDemoMode != true) - { - if (bool.TryParse(Environment.GetEnvironmentVariable("DEMO"), out var demo) && demo) - { - isDemoMode = demo; - } - } - GlobalConfiguration.IsDemoMode = isDemoMode; - - app.MapControllers(); - - //app.MapGet("/", () => - //{ - // return "ok"; - //}); - - //app.UseEndpoints(endpoints => - //{ - // //endpoints.MapControllers(); - - // // 配置回退路由 - // endpoints.MapFallbackToFile("index.html"); - //}); - - // 配置回退路由 - app.MapFallbackToFile("/", "index.html"); - - //app.Use(async (context, next) => - //{ - // await next(); - - // if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value)) - // { - // context.Request.Path = "/index.html"; // 将请求重定向到首页 - // await next(); - // } - //}); + var app = builder; // 在此处启动浏览器 // 从配置文件中读取 URL // 替换 * 以便于浏览器访问 - var url = builder.Configuration.GetSection("urls")?.Get()?.Replace("*", "localhost"); + var url = app.Services.GetService().GetSection("urls")?.Get()?.Replace("*", "localhost"); OpenBrowser(url); - // 启用 Windows Service 支持 - // install Microsoft.Extensions.Hosting.WindowsServices - //builder.Host.UseWindowsService(); - app.Run(); } catch (Exception ex) @@ -272,6 +62,14 @@ public static void Main(string[] args) } } + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }) + .UseSerilog(); + /// /// 打开默认浏览器的方法 /// @@ -303,9 +101,319 @@ private static void OpenBrowser(string url) { // 处理启动浏览器时可能出现的异常 // 在这里记录日志或者做其他处理 - Log.Error(ex, "打开默认浏览器异常 {@0}", url); } } } -} \ No newline at end of file +} + +//using MDriveSync.Core; +//using MDriveSync.Core.BaseAuth; +//using MDriveSync.Core.Dashboard; +//using MDriveSync.Core.Filters; +//using MDriveSync.Core.Middlewares; +//using MDriveSync.Infrastructure; +//using Microsoft.AspNetCore.Mvc; +//using Quartz.Logging; +//using Serilog; +//using Serilog.Debugging; +//using System.Diagnostics; + +//namespace MDriveSync.Client.API +//{ +// public class Program +// { +// public static void Main(string[] args) +// { +// var builder = WebApplication.CreateBuilder(args); + +// var env = builder.Environment; + +// //// 添加配置文件 +// //var configuration = builder.Configuration +// // .AddJsonFile($"appsettings.json", optional: true, reloadOnChange: true) + +// // // 环境变量中的 +// // .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true); + +// // //// 加载默认的 +// // //.AddJsonFile($"{ClientSettings.ClientSettingsPath}", optional: true, reloadOnChange: true); + +// //// 添加自定义配置文件 +// //builder.Configuration.AddJsonFile($"{ClientSettings.ClientSettingsPath}", optional: true, reloadOnChange: true); + +// //// 当打包为单个 exe 程序时,使用代码显式配置 Serilog,而不是完全依赖于配置文件。 +// //// 这可能导致 Serilog 在尝试自动发现和加载其扩展程序集(如 Sinks)时遇到问题 +// //// 显式配置 Serilog:在程序的 Main 方法中,使用代码显式配置 Serilog,而不是完全依赖于配置文件。 +// //// 即:要么手动列出 Sinks 或者通过下面这种方式 +// //var logOptions = new ConfigurationReaderOptions( +// // typeof(ConsoleLoggerConfigurationExtensions).Assembly); + +// // 配置 Serilog +// var logger = new LoggerConfiguration() +// .ReadFrom.Configuration(builder.Configuration); + +// //// 打包为单个 exe 文件,无法写日志,因此在这里配置写死 +// //.WriteTo.File("logs/log.txt", rollingInterval: RollingInterval.Day); + +// if (env.IsDevelopment()) +// { +// logger.MinimumLevel.Debug() +// .Enrich.FromLogContext(); + +// //.WriteTo.Console(); + +// // 使用 Serilog.Debugging.SelfLog.Enable(Console.Error) 来启用 Serilog 的自我诊断,这将帮助诊断配置问题。 +// SelfLog.Enable(Console.Error); +// } + +// Log.Logger = logger.CreateLogger(); + +// // Quartz Log +// var loggerFactory = new LoggerFactory().AddSerilog(Log.Logger); +// LogProvider.SetLogProvider(loggerFactory); + +// // 确保在应用程序结束时关闭并刷新日志 +// AppDomain.CurrentDomain.ProcessExit += (s, e) => Log.CloseAndFlush(); + +// try +// { +// Log.Information($"Current: {Directory.GetCurrentDirectory()}"); + +// // 使用 Serilog +// builder.Host.UseSerilog(); + +// // 作业客户端配置 +// builder.Services.Configure(builder.Configuration.GetSection("Client")); + +// //// API 视图模型验证 400 错误处理 +// //builder.Services.Configure(options => +// //{ +// // options.SuppressModelStateInvalidFilter = true; +// //}); + +// // API 异常过滤器 +// // API 方法/模型过滤器 +// builder.Services.AddControllers(options => +// { +// options.Filters.Add(); +// options.Filters.Add(); +// }); + +// // 自定义配置 API 行为选项 +// // 配置 api 视图模型验证 400 错误处理,需要在 AddControllers 之后配置 +// builder.Services.Configure(options => +// { +// // 方法1:禁用 ModelState 自动 400 错误处理,使用自定义方法验证 +// // 需要在控制器方法中手动调用 ModelState.IsValid,或者在控制器方法中使用 [ApiController] 特性,或者使用 ActionFilterAttribute 过滤器 +// //options.SuppressModelStateInvalidFilter = true; + +// // 方法2:自定义模型验证错误处理 +// options.InvalidModelStateResponseFactory = (context) => +// { +// var error = context.ModelState.Values.FirstOrDefault()?.Errors?.FirstOrDefault()?.ErrorMessage ?? "参数异常"; +// Log.Logger.Warning("参数异常 {@0} - {@1}", context.HttpContext?.Request?.GetUrl() ?? "", error); +// return new JsonResult(Result.Fail(error)); +// }; +// }); + +// // 后台服务 +// //builder.Services.AddHostedService(); + +// // 使用单例模式 + +// // 阿里云盘后台服务 +// builder.Services.AddSingleton(); +// builder.Services.AddHostedService(provider => provider.GetRequiredService()); + +// // 本地存储后台服务 +// builder.Services.AddSingleton(); +// builder.Services.AddHostedService(provider => provider.GetRequiredService()); + +// var app = builder.Build(); + +// //// 区分 API 和静态/客户端路由 +// //app.Use(async (context, next) => +// //{ +// // if (context.Request.Path.StartsWithSegments("/api")) +// // { +// // // 如果是 API 请求,继续执行后续中间件 +// // await next(); +// // } +// // //else +// // //{ +// // // app.MapFallbackToFile("index.html"); + +// // // //// 非 API 请求,尝试作为静态文件处理 +// // // //await next(); + +// // // //// 不是 API 请求,重写请求到 index.html +// // // //if (!Path.HasExtension(context.Request.Path.Value)) +// // // //{ +// // // // context.Request.Path = "/index.html"; +// // // // await next(); +// // // //} +// // //} +// //}); + +// app.UseStaticFiles(); + +// app.UseCors(builder => +// { +// builder.AllowAnyMethod().AllowAnyHeader().SetIsOriginAllowed(origin => true).AllowCredentials(); +// }); + +// // 添加基础认证 +// // 从环境变量获取配置,如果 appsettings.json 中的配置为空 +// var userFromConfig = builder.Configuration["BasicAuth:User"]; +// var passwordFromConfig = builder.Configuration["BasicAuth:Password"]; +// var user = string.IsNullOrEmpty(userFromConfig) ? +// Environment.GetEnvironmentVariable("BASIC_AUTH_USER") : userFromConfig; + +// var password = string.IsNullOrEmpty(passwordFromConfig) ? +// Environment.GetEnvironmentVariable("BASIC_AUTH_PASSWORD") : passwordFromConfig; + +// // 如果账号和密码 +// if (!string.IsNullOrWhiteSpace(user) && !string.IsNullOrWhiteSpace(password)) +// { +// var basicAuth = new BasicAuthAuthorizationUser() +// { +// Login = user, +// PasswordClear = password +// }; +// var filter = new BasicAuthAuthorizationFilterOptions +// { +// RequireSsl = false, +// SslRedirect = false, +// LoginCaseSensitive = true, +// Users = new[] { basicAuth } +// }; +// var options = new DashboardOptions +// { +// Authorization = new[] { new BasicAuthAuthorizationFilter(filter) } +// }; + +// // 全局 +// app.UseMiddleware(options); + +// //// 部分 +// //app.UseWhen(context => context.Request.Path.StartsWithSegments("/api"), appBuilder => +// //{ +// // appBuilder.UseMiddleware(options); +// //}); +// } + +// // 从配置或环境变量中获取是否开启只读模式 +// var isReadOnlyMode = builder.Configuration.GetSection("ReadOnly").Get(); +// if (isReadOnlyMode != true) +// { +// if (bool.TryParse(Environment.GetEnvironmentVariable("READ_ONLY"), out var ro) && ro) +// { +// isReadOnlyMode = ro; +// } +// } + +// if (isReadOnlyMode == true) +// { +// app.UseMiddleware(isReadOnlyMode); +// } + +// // 演示模式处理 +// var isDemoMode = builder.Configuration.GetSection("Demo").Get(); +// if (isDemoMode != true) +// { +// if (bool.TryParse(Environment.GetEnvironmentVariable("DEMO"), out var demo) && demo) +// { +// isDemoMode = demo; +// } +// } +// GlobalConfiguration.IsDemoMode = isDemoMode; + +// app.MapControllers(); + +// //app.MapGet("/", () => +// //{ +// // return "ok"; +// //}); + +// //app.UseEndpoints(endpoints => +// //{ +// // //endpoints.MapControllers(); + +// // // 配置回退路由 +// // endpoints.MapFallbackToFile("index.html"); +// //}); + +// // 配置回退路由 +// app.MapFallbackToFile("/", "index.html"); + +// //app.Use(async (context, next) => +// //{ +// // await next(); + +// // if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value)) +// // { +// // context.Request.Path = "/index.html"; // 将请求重定向到首页 +// // await next(); +// // } +// //}); + +// // 在此处启动浏览器 +// // 从配置文件中读取 URL +// // 替换 * 以便于浏览器访问 +// var url = builder.Configuration.GetSection("urls")?.Get()?.Replace("*", "localhost"); +// OpenBrowser(url); + +// // 启用 Windows Service 支持 +// // install Microsoft.Extensions.Hosting.WindowsServices +// //builder.Host.UseWindowsService(); + +// app.Run(); +// } +// catch (Exception ex) +// { +// Log.Fatal(ex, "应用启动失败"); +// } +// finally +// { +// Log.CloseAndFlush(); +// } +// } + +// /// +// /// 打开默认浏览器的方法 +// /// +// /// +// private static void OpenBrowser(string url) +// { +// try +// { +// if (string.IsNullOrWhiteSpace(url)) +// { +// return; +// } + +// // 根据不同的操作系统使用不同的命令 +// if (GlobalConfiguration.IsWindows()) +// { +// Process.Start(new ProcessStartInfo("cmd", $"/c start {url}")); // Windows +// } +// else if (GlobalConfiguration.IsLinux()) +// { +// // Process.Start("xdg-open", url); // Linux +// } +// else if (GlobalConfiguration.IsMacOS()) +// { +// Process.Start("open", url); // MacOS +// } +// } +// catch (Exception ex) +// { +// // 处理启动浏览器时可能出现的异常 +// // 在这里记录日志或者做其他处理 + +// Log.Error(ex, "打开默认浏览器异常 {@0}", url); +// } +// } +// } +//} \ No newline at end of file diff --git a/src/MDriveSync.Client.API/Startup.cs b/src/MDriveSync.Client.API/Startup.cs new file mode 100644 index 0000000..8cd0f16 --- /dev/null +++ b/src/MDriveSync.Client.API/Startup.cs @@ -0,0 +1,126 @@ +锘縰sing MDriveSync.Core; +using MDriveSync.Core.BaseAuth; +using MDriveSync.Core.Dashboard; +using MDriveSync.Core.Filters; +using MDriveSync.Core.Middlewares; +using MDriveSync.Infrastructure; +using Microsoft.AspNetCore.Mvc; +using Serilog; + +namespace MDriveSync.Client.API +{ + public class Startup + { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + public void ConfigureServices(IServiceCollection services) + { + services.Configure(Configuration.GetSection("Client")); + + // API 寮傚父杩囨护鍣 + // API 鏂规硶/妯″瀷杩囨护鍣 + services.AddControllers(options => + { + options.Filters.Add(); + options.Filters.Add(); + }); + + // 鑷畾涔夐厤缃 API 琛屼负閫夐」 + // 閰嶇疆 api 瑙嗗浘妯″瀷楠岃瘉 400 閿欒澶勭悊锛岄渶瑕佸湪 AddControllers 涔嬪悗閰嶇疆 + services.Configure(options => + { + options.InvalidModelStateResponseFactory = (context) => + { + var error = context.ModelState.Values.FirstOrDefault()?.Errors?.FirstOrDefault()?.ErrorMessage ?? "鍙傛暟寮傚父"; + Log.Logger.Warning("鍙傛暟寮傚父 {@0} - {@1}", context.HttpContext?.Request?.GetUrl() ?? "", error); + return new JsonResult(Result.Fail(error)); + }; + }); + + services.AddSingleton(); + services.AddHostedService(provider => provider.GetRequiredService()); + + services.AddSingleton(); + services.AddHostedService(provider => provider.GetRequiredService()); + } + + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseStaticFiles(); + + app.UseCors(builder => + { + builder.AllowAnyMethod().AllowAnyHeader().SetIsOriginAllowed(origin => true).AllowCredentials(); + }); + + var userFromConfig = Configuration["BasicAuth:User"]; + var passwordFromConfig = Configuration["BasicAuth:Password"]; + var user = string.IsNullOrEmpty(userFromConfig) ? Environment.GetEnvironmentVariable("BASIC_AUTH_USER") : userFromConfig; + var password = string.IsNullOrEmpty(passwordFromConfig) ? Environment.GetEnvironmentVariable("BASIC_AUTH_PASSWORD") : passwordFromConfig; + + if (!string.IsNullOrWhiteSpace(user) && !string.IsNullOrWhiteSpace(password)) + { + var basicAuth = new BasicAuthAuthorizationUser() + { + Login = user, + PasswordClear = password + }; + var filter = new BasicAuthAuthorizationFilterOptions + { + RequireSsl = false, + SslRedirect = false, + LoginCaseSensitive = true, + Users = new[] { basicAuth } + }; + var options = new DashboardOptions + { + Authorization = new[] { new BasicAuthAuthorizationFilter(filter) } + }; + + app.UseMiddleware(options); + } + + var isReadOnlyMode = Configuration.GetSection("ReadOnly").Get(); + if (isReadOnlyMode != true) + { + if (bool.TryParse(Environment.GetEnvironmentVariable("READ_ONLY"), out var ro) && ro) + { + isReadOnlyMode = ro; + } + } + + if (isReadOnlyMode == true) + { + app.UseMiddleware(isReadOnlyMode); + } + + var isDemoMode = Configuration.GetSection("Demo").Get(); + if (isDemoMode != true) + { + if (bool.TryParse(Environment.GetEnvironmentVariable("DEMO"), out var demo) && demo) + { + isDemoMode = demo; + } + } + GlobalConfiguration.IsDemoMode = isDemoMode; + + app.UseRouting(); + + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + endpoints.MapFallbackToFile("index.html"); + }); + } + } +} \ No newline at end of file