diff --git a/Solution/SiteLibrary/Controllers/AdminController.cs b/Solution/SiteLibrary/Controllers/AdminController.cs new file mode 100644 index 000000000..821ea7d97 --- /dev/null +++ b/Solution/SiteLibrary/Controllers/AdminController.cs @@ -0,0 +1,48 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using System.IO; + +namespace SiteLibrary.Controllers +{ + public class AdminController : Controller + { + private readonly IWebHostEnvironment _env; + private readonly ILogger _logger; + private readonly IHostApplicationLifetime _appLifetime; + + public AdminController(IWebHostEnvironment env, ILogger logger, IHostApplicationLifetime appLifetime) + { + this._env = env; + this._logger = logger; + this._appLifetime = appLifetime; + } + + public IActionResult Index() + { + return View(); + } + + public IActionResult UpdateDB() + { + using var db = new MyDbContext(new DbContextOptionsBuilder().UseSqlite($"Data Source={Path.Combine(this._env.WebRootPath, "data.db")}").Options); + db.Seed(this._env.WebRootPath, false, o => this._logger.LogInformation(o), o => this._logger.LogError(o)); + this._env.WebRootPath.UpdateList(o => this._logger.LogInformation(o)); + return RedirectToAction("Index"); + } + + public IActionResult UpdateList() + { + this._env.WebRootPath.UpdateList(o => this._logger.LogInformation(o)); + return RedirectToAction("Index"); + } + + public IActionResult Restart() + { + this._appLifetime.StopApplication(); + return RedirectToAction("Index"); + } + } +} diff --git a/Solution/SiteLibrary/ObjectExtensions.cs b/Solution/SiteLibrary/ObjectExtensions.cs index d4ac27d02..729c7a866 100644 --- a/Solution/SiteLibrary/ObjectExtensions.cs +++ b/Solution/SiteLibrary/ObjectExtensions.cs @@ -35,6 +35,7 @@ namespace SiteLibrary stream.Dispose(); return BitConverter.ToString(hash).Replace("-", "").ToLower(); } + public static string ExtToLower(this string file) { if (!string.IsNullOrEmpty(file)) diff --git a/Solution/SiteLibrary/Views/Admin/Index.cshtml b/Solution/SiteLibrary/Views/Admin/Index.cshtml new file mode 100644 index 000000000..360c894e2 --- /dev/null +++ b/Solution/SiteLibrary/Views/Admin/Index.cshtml @@ -0,0 +1,30 @@ +@{ + Layout = null; +} + + + + + + Home + + + + + + \ No newline at end of file diff --git a/Solution/TestServer/Controllers/HomeController.cs b/Solution/TestServer/Controllers/HomeController.cs index 1ae6bb987..ae608ee93 100644 --- a/Solution/TestServer/Controllers/HomeController.cs +++ b/Solution/TestServer/Controllers/HomeController.cs @@ -1,61 +1,13 @@ -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging; -using System; -using System.IO; -using System.Reflection; +using Microsoft.AspNetCore.Mvc; namespace TestServer.Controllers { public class HomeController : Controller { - private readonly IWebHostEnvironment _env; - private readonly ILogger _logger; - private readonly DbContext _dbContext; - - public HomeController(IWebHostEnvironment env, ILogger logger,DbContext dbContext) - { - this._env = env; - this._logger = logger; - this._dbContext = dbContext; - } public IActionResult Index() { return View(); } - - public IActionResult UpdateDB() - { - var builder = new DbContextOptionsBuilder(); - builder.UseSqlite($"Data Source={Path.Combine(this._env.WebRootPath, "data.db")}"); - this._dbContext.GetType().InvokeMember("Seed", - BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, - null, - null, - new object[]{ - this._dbContext, this._env.WebRootPath, false, (Action)(o => this._logger.LogInformation(o)), (Action)(o => this._logger.LogError(o)) - }); - - //context.Seed(this._env.WebRootPath, false, o => this._logger.LogInformation(o), o => this._logger.LogError(o)); - this._env.WebRootPath.GetType().InvokeMember("UpdateList", - BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, - null, - null, - new object[] { (Action)(o => this._logger.LogInformation(o))}); - return RedirectToAction("Index"); - } - - public IActionResult UpdateList() - { - //this._env.WebRootPath.UpdateList(o => this._logger.LogInformation(o)); - this._env.WebRootPath.GetType().InvokeMember("UpdateList", - BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, - null, - null, - new object[] { (Action)(o => this._logger.LogInformation(o)) }); - return RedirectToAction("Index"); - } } } \ No newline at end of file diff --git a/Solution/TestServer/ObjectExtensions.cs b/Solution/TestServer/ObjectExtensions.cs new file mode 100644 index 000000000..e192f1f1d --- /dev/null +++ b/Solution/TestServer/ObjectExtensions.cs @@ -0,0 +1,18 @@ +using System; +using System.IO; +using System.Security.Cryptography; + +namespace TestServer +{ + public static class ObjectExtensions + { + public static string Md5(this string file) + { + using var md5 = MD5.Create(); + using var stream = File.OpenRead(file); + var hash = md5.ComputeHash(stream); + stream.Dispose(); + return BitConverter.ToString(hash).Replace("-", "").ToLower(); + } + } +} \ No newline at end of file diff --git a/Solution/TestServer/Program.cs b/Solution/TestServer/Program.cs index dfcf27ea4..1f064f179 100644 --- a/Solution/TestServer/Program.cs +++ b/Solution/TestServer/Program.cs @@ -6,35 +6,45 @@ using Serilog.Core; using Serilog.Events; using System; using System.IO; +using System.Threading; namespace TestServer { public class Program { + private static CancellationTokenSource cts = new CancellationTokenSource(); + public static void Main(string[] args) { Log.Logger = new LoggerConfiguration() .MinimumLevel.Override("Microsoft", LogEventLevel.Information) .MinimumLevel.Debug() - .WriteTo.File(Path.Combine(AppContext.BaseDirectory, "logs", "app.log.txt"), shared: true, rollOnFileSizeLimit: true, fileSizeLimitBytes: 1024 * 1024 * 1024, rollingInterval: RollingInterval.Day, retainedFileCountLimit: 7, levelSwitch: new LoggingLevelSwitch(LogEventLevel.Information)) - .WriteTo.File(Path.Combine(AppContext.BaseDirectory, "logs", "app.err.txt"), shared: true, rollOnFileSizeLimit: true, fileSizeLimitBytes: 1024 * 1024 * 1024, rollingInterval: RollingInterval.Day, retainedFileCountLimit: 7, levelSwitch: new LoggingLevelSwitch(LogEventLevel.Error)) + .WriteTo.File(Path.Combine(Directory.GetCurrentDirectory(), "logs", "app.log.txt"), shared: true, rollOnFileSizeLimit: true, fileSizeLimitBytes: 1024 * 1024 * 1024, rollingInterval: RollingInterval.Day, retainedFileCountLimit: 7, levelSwitch: new LoggingLevelSwitch(LogEventLevel.Information)) + .WriteTo.File(Path.Combine(Directory.GetCurrentDirectory(), "logs", "app.err.txt"), shared: true, rollOnFileSizeLimit: true, fileSizeLimitBytes: 1024 * 1024 * 1024, rollingInterval: RollingInterval.Day, retainedFileCountLimit: 7, levelSwitch: new LoggingLevelSwitch(LogEventLevel.Error)) .CreateLogger(); try { - Log.Information("server start"); - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => - { - var config = new ConfigurationBuilder() - .SetBasePath(Directory.GetCurrentDirectory()) - .AddJsonFile("appsettings.json", optional: false) - .Build(); - webBuilder.UseUrls(config.GetValue("server.urls", "http://*:9505")); - webBuilder.UseStartup(); - }) - .Build() - .Run(); - Log.Information("server exit"); + while(!cts.IsCancellationRequested) + { + Log.Information("server start"); + Host.CreateDefaultBuilder(args) + .UseSerilog() + .ConfigureWebHostDefaults(webBuilder => + { + var config = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", optional: false) + .Build(); + webBuilder.UseUrls(config.GetValue("server.urls", "http://*:9505")); + webBuilder.CaptureStartupErrors(true); + webBuilder.UseSetting(WebHostDefaults.DetailedErrorsKey, "true"); + webBuilder.UseStartup(); + }) + .Build() + .Run(); + Log.Information("server exit"); + } + } catch (Exception ex) { diff --git a/Solution/TestServer/Startup.cs b/Solution/TestServer/Startup.cs index f79f18f94..7dfa1c694 100644 --- a/Solution/TestServer/Startup.cs +++ b/Solution/TestServer/Startup.cs @@ -13,6 +13,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Reflection; using System.Runtime.Loader; using System.Text.Encodings.Web; using System.Text.Unicode; @@ -25,14 +26,39 @@ namespace TestServer public IWebHostEnvironment Env { get; } public IConfiguration Configuration { get; } private readonly string _origins = "AllowAllHeaders"; - private List _myMiddlewares = new List(); - private List _startups = new List(); private string _url; + private Dictionary assemblyList = new Dictionary(); public Startup(IWebHostEnvironment env, IConfiguration configuration) { this.Env = env; this.Configuration = configuration; + this.Init(); + } + + private void Init() + { + var pluginsPath = Path.Combine(this.Env.WebRootPath, "plugin"); + var pluginsPathCopy = Path.Combine(this.Env.WebRootPath, "plugin", "copy"); + Directory.CreateDirectory(pluginsPath); + Directory.CreateDirectory(pluginsPathCopy); + var files = Directory.GetFiles(pluginsPath); + foreach (var file in files) + { + var fileName = Path.GetFileName(file); + var copyFile = Path.Combine(pluginsPathCopy, fileName); + if (!File.Exists(copyFile) || file.Md5() != copyFile.Md5()) + { + File.Copy(file, copyFile, true); + } + } + var assemblyFiles = Directory.GetFiles(pluginsPathCopy, "*.dll", SearchOption.AllDirectories); + foreach (var file in assemblyFiles) + { + using var fs = new FileStream(file, FileMode.Open); + var assembly = new AssemblyLoadContext(file, true).LoadFromStream(fs); + this.assemblyList.Add(file,assembly); + } } public void ConfigureServices(IServiceCollection services) @@ -50,16 +76,25 @@ namespace TestServer services.AddSingleton(MyActionDescriptorChangeProvider.Instance); services.AddSingleton(MyActionDescriptorChangeProvider.Instance); services.AddHttpClient(); - services.AddSignalR(o => o.EnableDetailedErrors = true).AddJsonProtocol(); services.AddControllersWithViews() .AddNewtonsoftJson(o => { o.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; }) .ConfigureApplicationPartManager(ConfigureApplicationParts); - foreach (var item in _startups) + foreach (var assembly in this.assemblyList) { - (item.Assembly.CreateInstance(item.FullName) as IStartup).ConfigureServices(services); + try + { + assembly.Value.GetTypes() + .Where(o => typeof(IStartup).IsAssignableFrom(o)) + .ToList() + .ForEach(o => (assembly.Value.CreateInstance(o.FullName) as IStartup).ConfigureServices(services)); + } + catch (Exception ex) + { + Log.Error(ex.ToString()); + } } } @@ -85,13 +120,23 @@ namespace TestServer app.UseDeveloperExceptionPage(); app.UseCors(_origins); - foreach (var item in _startups) - { - (item.Assembly.CreateInstance(item.FullName) as IStartup).Configure(app); - } - foreach (var item in this._myMiddlewares) + foreach (var assembly in this.assemblyList) { - app.UseMiddleware(item); + try + { + assembly.Value.GetTypes() + .Where(o => typeof(IStartup).IsAssignableFrom(o)) + .ToList() + .ForEach(o => (assembly.Value.CreateInstance(o.FullName) as IStartup).Configure(app)); + assembly.Value.GetTypes() + .Where(o => o.Name.EndsWith("Middleware")) + .ToList() + .ForEach(o => app.UseMiddleware(o)); + } + catch (Exception ex) + { + Log.Error(ex.ToString()); + } } app.UseStaticFiles(new StaticFileOptions { @@ -105,12 +150,6 @@ namespace TestServer app.UseAuthorization(); app.UseEndpoints(endpoints => { - //endpoints.MapHub("/hub", o => - //{ - // o.ApplicationMaxBufferSize = long.MaxValue; - // o.TransportMaxBufferSize = long.MaxValue; - //}); - endpoints.MapControllerRoute( name: "areas", pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}"); @@ -124,27 +163,17 @@ namespace TestServer private void ConfigureApplicationParts(ApplicationPartManager apm) { Log.Logger.Information("Startup>ConfigureApplicationParts"); - var pluginsPath = Path.Combine(this.Env.WebRootPath, "plugin", "copy"); - if (!Directory.Exists(pluginsPath)) - { - Directory.CreateDirectory(pluginsPath); - } - var assemblyFiles = Directory.GetFiles(pluginsPath, "*.dll", SearchOption.AllDirectories); - foreach (var assemblyFile in assemblyFiles) + foreach (var assembly in assemblyList) { try { - using var fs = new FileStream(assemblyFile, FileMode.Open); - var assembly = new AssemblyLoadContext(assemblyFile, true).LoadFromStream(fs); - if (assemblyFile.EndsWith(".Views.dll")) + if (assembly.Key.EndsWith(".Views.dll")) { - apm.ApplicationParts.Add(new MyCompiledRazorAssemblyPart(assembly)); + apm.ApplicationParts.Add(new MyCompiledRazorAssemblyPart(assembly.Value)); } else { - apm.ApplicationParts.Add(new MyAssemblyPart(assembly)); - this._myMiddlewares.AddRange(assembly.GetTypes().Where(o => o.Name.EndsWith("Middleware"))); - this._startups.AddRange(assembly.GetTypes().Where(o => typeof(IStartup).IsAssignableFrom(o))); + apm.ApplicationParts.Add(new MyAssemblyPart(assembly.Value)); } } catch (Exception ex) diff --git a/Solution/TestServer/Views/Home/Index.cshtml b/Solution/TestServer/Views/Home/Index.cshtml index e1b7c70d2..9cda5090b 100644 --- a/Solution/TestServer/Views/Home/Index.cshtml +++ b/Solution/TestServer/Views/Home/Index.cshtml @@ -22,8 +22,6 @@ \ No newline at end of file diff --git a/Solution/TestServer/wwwroot/plugin/copy/webapi.Views.dll b/Solution/TestServer/wwwroot/plugin/copy/webapi.Views.dll new file mode 100644 index 000000000..43440005d Binary files /dev/null and b/Solution/TestServer/wwwroot/plugin/copy/webapi.Views.dll differ diff --git a/Solution/TestServer/wwwroot/plugin/copy/webapi.dll b/Solution/TestServer/wwwroot/plugin/copy/webapi.dll new file mode 100644 index 000000000..48dd4079a Binary files /dev/null and b/Solution/TestServer/wwwroot/plugin/copy/webapi.dll differ diff --git a/Solution/TestServer/wwwroot/plugin/webapi.Views.dll b/Solution/TestServer/wwwroot/plugin/webapi.Views.dll index 5407a9e10..43440005d 100644 Binary files a/Solution/TestServer/wwwroot/plugin/webapi.Views.dll and b/Solution/TestServer/wwwroot/plugin/webapi.Views.dll differ diff --git a/Solution/TestServer/wwwroot/plugin/webapi.dll b/Solution/TestServer/wwwroot/plugin/webapi.dll index fa75cd3fe..48dd4079a 100644 Binary files a/Solution/TestServer/wwwroot/plugin/webapi.dll and b/Solution/TestServer/wwwroot/plugin/webapi.dll differ