Program.cs 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. using IES.ExamServer.DI;
  2. using IES.ExamServer.DI.SignalRHost;
  3. using IES.ExamServer.Helper;
  4. using Microsoft.AspNetCore.Hosting.Server.Features;
  5. using Microsoft.AspNetCore.Hosting.Server;
  6. using Microsoft.AspNetCore.SpaServices;
  7. using Microsoft.AspNetCore.StaticFiles;
  8. using Microsoft.Extensions.Caching.Memory;
  9. using System.Text.Json;
  10. using System.Text.Json.Nodes;
  11. using VueCliMiddleware;
  12. using IES.ExamServer.Services;
  13. using System.Text;
  14. using IES.ExamServer.Filters;
  15. using IES.ExamServer.Helpers;
  16. using Microsoft.Extensions.Hosting;
  17. using System.Security.Principal;
  18. using Microsoft.Extensions.FileProviders;
  19. using System.Text.Encodings.Web;
  20. using System.Text.Unicode;
  21. using Microsoft.Extensions.Logging;
  22. using System.Runtime.InteropServices;
  23. using NLog.Extensions.Logging;
  24. namespace IES.ExamServer
  25. {
  26. public class Program: IDisposable
  27. {
  28. public async static Task Main(string[] args)
  29. {
  30. Console.OutputEncoding = Encoding.UTF8;
  31. if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)||RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
  32. { }
  33. else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
  34. {
  35. }
  36. //
  37. //var mutex = new Mutex(true, "IES.ExamServer", out var createdNew);
  38. //if (!createdNew)
  39. //{
  40. // // 防止多开,重复启动
  41. // Console.WriteLine("The application is already running.");
  42. // return;
  43. //}
  44. //ProcessHelper.CloseConhost();
  45. //AppDomain.CurrentDomain.ProcessExit += OnExit;
  46. var builder = WebApplication.CreateBuilder(args);
  47. string path = $"{builder.Environment.ContentRootPath}/Configs";
  48. //builder.WebHost.UseKestrel(options =>
  49. //{
  50. // options.ListenAnyIP(5001, listenOptions =>
  51. // {
  52. // listenOptions.UseHttps($"{path}/cert.pfx", "cdhabook") ;
  53. // });
  54. //});
  55. builder.Configuration.SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
  56. builder.Services.AddSpaStaticFiles(opt => opt.RootPath = "ClientApp/dist");
  57. // Add services to the container.
  58. builder.Services.AddControllers().AddJsonOptions(options =>
  59. {
  60. // 设置 JSON 序列化选项
  61. options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All); // 允许所有 Unicode 字符
  62. options.JsonSerializerOptions.WriteIndented = true; // 格式化输出(可选)
  63. }); ;
  64. builder.Services.AddHttpClient();
  65. builder.Services.AddSignalR();
  66. builder.Services.AddHttpContextAccessor();
  67. //此处能在Linux及MacOS运行,
  68. //Windows的路径是LocalApplicationData Path: C:\Users\john\AppData\Local
  69. //Linux的路径是LocalApplicationData Path: /home/john/.local/share,
  70. //MacOS 的路径LocalApplicationData Path: /Users/john/Library/Application Support
  71. string localAppDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
  72. //string dbpath = $"{localAppDataPath}\\ExamServer\\LiteDB";
  73. string dbpath = Path.Combine(localAppDataPath, "ExamServer", "LiteDB");
  74. if (!System.IO.Directory.Exists(dbpath))
  75. {
  76. System.IO.Directory.CreateDirectory(dbpath);
  77. }
  78. string liteDBPath = $"Filename={dbpath}/data.db;Connection=shared";
  79. var connections_LiteDB = new List<LiteDBFactoryOptions>
  80. {
  81. new LiteDBFactoryOptions { Name = "Master", Connectionstring = liteDBPath}
  82. };
  83. builder.Services.AddLiteDB(connections_LiteDB);
  84. builder.Services.AddMemoryCache();
  85. // 注册 ConnectionService 为单例
  86. builder.Services.AddSingleton<CenterServiceConnectionService>();
  87. builder.Services.AddSingleton<ServiceInitializer>();
  88. builder.Services.AddCors(options =>
  89. {
  90. //options.AddDefaultPolicy(
  91. //builder =>
  92. //{
  93. // builder.AllowAnyOrigin()
  94. // .AllowAnyHeader()
  95. // .AllowAnyMethod();
  96. //});
  97. options.AddPolicy("any", builder =>
  98. {
  99. builder.SetIsOriginAllowed(x=>true)
  100. .AllowAnyMethod()
  101. .AllowAnyHeader()
  102. .AllowCredentials();
  103. });
  104. });
  105. builder.Services.AddMvcFilter<AuthTokenActionFilter>();
  106. // 添加自定义日志提供程序
  107. //builder.Logging.ClearProviders();
  108. //bool enableConsoleOutput = true;
  109. //builder.Logging.AddProvider(new CustomFileLoggerProvider(Path.Combine(Directory.GetCurrentDirectory(), "Logs"), enableConsoleOutput));
  110. // 添加日志服务
  111. builder.Logging.ClearProviders();
  112. builder.Logging.AddNLog();
  113. builder.Services.AddHostedService<SignalRCloudClientHub>();
  114. var app = builder.Build();
  115. // Configure the HTTP request pipeline.
  116. if (!app.Environment.IsDevelopment())
  117. {
  118. app.UseExceptionHandler("/Home/Error");
  119. // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
  120. app.UseHsts();
  121. }
  122. else { app.UseDeveloperExceptionPage(); }
  123. app.UseHttpsRedirection();
  124. app.UseDefaultFiles();
  125. var contentTypeProvider = new FileExtensionContentTypeProvider();
  126. contentTypeProvider.Mappings[".txt"] = "text/plain";
  127. contentTypeProvider.Mappings[".jpg"] = "image/jpeg";
  128. contentTypeProvider.Mappings[".jpeg"] = "image/jpeg";
  129. contentTypeProvider.Mappings[".png"] = "image/png";
  130. contentTypeProvider.Mappings[".html"] = "text/html";
  131. contentTypeProvider.Mappings[".js"] = "application/javascript";
  132. contentTypeProvider.Mappings[".css"] = "text/css";
  133. contentTypeProvider.Mappings[".mp4"] = "video/mp4";
  134. contentTypeProvider.Mappings[".mp3"] = "audio/mpeg";
  135. contentTypeProvider.Mappings[".json"] = "application/json";
  136. contentTypeProvider.Mappings[".pdf"] = "application/pdf";
  137. string packagePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "package");
  138. if (!Directory.Exists(packagePath))
  139. {
  140. Directory.CreateDirectory(packagePath);
  141. }
  142. //new StaticFileOptions
  143. //{
  144. // FileProvider = new PhysicalFileProvider(
  145. // Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "package")),
  146. // RequestPath = "/package",
  147. // ContentTypeProvider = contentTypeProvider,
  148. //}
  149. app.UseStaticFiles();
  150. app.UseRouting();
  151. app.UseCors("any");
  152. app.UseAuthorization();
  153. app.MapHub<SignalRExamServerHub>("/signalr/exam").RequireCors("any");
  154. app.UseEndpoints(endpoints =>
  155. {
  156. // endpoints.MapHub<SignalRExamServerHub>("/signalr/exam").RequireCors("any");
  157. endpoints.MapControllers();
  158. // NOTE: VueCliProxy is meant for developement and hot module reload
  159. // NOTE: SSR has not been tested
  160. // Production systems should only need the UseSpaStaticFiles() (above)
  161. // You could wrap this proxy in either
  162. // if (System.Diagnostics.Debugger.IsAttached)
  163. // or a preprocessor such as #if DEBUG
  164. /*
  165. npm install -g @vue
  166. vue create app
  167. */
  168. #if DEBUG
  169. endpoints.MapToVueCliProxy(
  170. "{*path}",
  171. new SpaOptions { SourcePath = "ClientApp" },
  172. npmScript: (System.Diagnostics.Debugger.IsAttached) ? "serve" : null,
  173. // regex: "Compiled successfully",
  174. forceKill: true
  175. );
  176. #else
  177. endpoints.MapFallbackToFile("index.html");
  178. #endif
  179. });
  180. // 获取 ServiceInitializer 实例并初始化
  181. var connectionManager = app.Services.GetRequiredService<ServiceInitializer>();
  182. await connectionManager.InitializeAsync();
  183. await app.RunAsync();
  184. }
  185. //static void OnExit(object sender, EventArgs e)
  186. //{
  187. // Console.WriteLine("正在退出程序...");
  188. // // 执行任何需要的清理工作
  189. // // 例如: 保存状态,关闭文件和数据库连接等
  190. // // 通过调用 Environment.Exit 来结束进程
  191. // Environment.Exit(0);
  192. //}
  193. public void Dispose()
  194. {
  195. // 清理代码
  196. //Console.WriteLine("正在退出...");
  197. // 释放资源、关闭连接等
  198. }
  199. }
  200. public class SystemInfo
  201. {
  202. public string? id { get; set; }
  203. public string? version { get; set; }
  204. public string? description { get; set; }
  205. public long nowtime { get; set; }
  206. public string? region { get; set; }
  207. public string? ip { get; set; }
  208. public string? date { get; set; }
  209. public string? centerUrl { get; set; }
  210. }
  211. }