protected override void ProcessQueueEntries(List <ExceptionWrapper> entryCollection) { try { DateTime?lastFailedToLogToStoreDate = null; foreach (var ew in entryCollection) { try { AddExceptionToDB(ew); } catch (Exception ee) { // prevent logging failures too often if (!lastFailedToLogToStoreDate.HasValue || DateTime.Now.Subtract(lastFailedToLogToStoreDate.Value).TotalSeconds >= 25) { Log.Error(ee, $"Failed to log exception to DB store. EP={ew.EndpointKey}; sID={ew.sId};"); Log.Error($"Original: {ew.message}; stack=\r\n{ew.stackTrace}"); lastFailedToLogToStoreDate = DateTime.Now; } } } } catch (Exception ex) { Log.Error(ex, "ExceptionLogger::ProcessMessagesLoop failed"); SessionLog.Error("ExceptionLogger::ProcessMessagesLoop failed"); SessionLog.Exception(ex); } }
private Assembly ResolveReference(AssemblyLoadContext ctx, AssemblyName asmName) { try { // try and find relative to existing assebmlies loaded in ctx foreach (var asm in ctx.Assemblies) { var fi = new FileInfo(asm.Location); var path = Path.Combine(fi.DirectoryName, asmName.Name + ".dll"); if (File.Exists(path)) { try { var loadedAsm = ctx.LoadFromAssemblyPath(path); if (loadedAsm != null) { return(loadedAsm); } } catch { } } } SessionLog.Error($"Failed to resolve {asmName.FullName} in context {ctx.Name}"); return(null); } catch (Exception ex) { SessionLog.Error($"(Exception) Failed to resolve {asmName.FullName} in context {ctx.Name}. {ex.ToString()}"); return(null); } }
private static PluginSetParameterValue GetParameterValueFromPlugins(CachedRoutine routine, string parameterName, List <ExecutionPlugin> plugins) { foreach (var plugin in plugins) { try { var val = plugin.GetParameterValue(routine.Schema, routine.Routine, parameterName); if (val != PluginSetParameterValue.DontSet) { return(val); } } catch (Exception ex) { SessionLog.Error("Plugin {0} GetParameterValue failed", plugin.Name); SessionLog.Exception(ex); } } return(PluginSetParameterValue.DontSet); }
private void CompileCodeIntoAssemblyContext(InlineModuleManifestEntry inlineEntry, string code) { var ctxName = $"Inline Plugin Context {++_asmCtxCounter}"; var pluginPath = Path.GetFullPath("plugins"); var asmCtx = new PluginAssemblyLoadContext(pluginPath, ctxName, true /*enable unloading*/); ASM_CTXES.Add(asmCtx); SessionLog.Info($"Created {ctxName} for {inlineEntry.Name}".PadRight(35)); var assemblyBytes = CSharpCompilerHelper.CompileIntoAssembly(inlineEntry.Name, code, out var problems); if ((problems != null && problems.Count == 0)) { Assembly assembly = null; try { using (var ms = new MemoryStream(assemblyBytes)) { assembly = asmCtx.LoadFromStream(ms); ParseAndLoadPluginAssembly(asmCtx, assembly, inlineEntry.Id); } } catch (Exception ee) { SessionLog.Error($"Failed to load inline plugin assembly '{assembly?.FullName}' {inlineEntry.Name}/{inlineEntry.Id}. See exception that follows."); SessionLog.Exception(ee); } } else { SessionLog.Error($"Inline plugin {inlineEntry.Name} ({inlineEntry.Id}) failed to compile with the following error(s): {string.Join(", ", problems)}"); } }
public void Run() { try { Thread.CurrentThread.Name = "WorkerThread " + this.Endpoint.Pedigree; this.Status = "Started"; this.IsRunning = true; this.IsOutputFilesDirty = false; //DateTime lastSavedDate = DateTime.Now; var cache = this.Endpoint.CachedRoutines; if (cache != null && cache.Count > 0) { this.MaxRowDate = cache.Max(c => c.RowVer); } int connectionOpenErrorCnt = 0; if (this.Endpoint?.MetadataConnection?.ConnectionStringDecrypted == null) { this.IsRunning = false; this.Status = $"Endpoint '{this.Endpoint?.Pedigree ?? "(null)"}' does not have a valid metadata connection configured."; this.log.Error(this.Status); SessionLog.Error(this.Status); return; } var exceptionThrottler = new SortedList <DateTime, Exception>(); while (this.IsRunning) { // look for new instructions first lock (_instructionQueue) { while (_instructionQueue.Count > 0) { var ins = _instructionQueue.Dequeue(); if (ins.Type == WorkerInstructionType.RegenAllFiles) { this.ForceGenerateAllOutputFiles(this.Endpoint); } else if (ins.Type == WorkerInstructionType.RegenSpecificFile) { this.ForceGenerateOutputFile(this.Endpoint, ins.JsFile); } } } isIterationDirty = false; string connectionStringRefForLog = null; try { if (!string.IsNullOrEmpty(Endpoint.PullMetadataFromEndpointId)) { var ep = Settings.SettingsInstance.Instance.FindEndpointById(Endpoint.PullMetadataFromEndpointId); if (ep != null) { this.Status = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm")} - Metadata pulled from {ep.Pedigree}"; } else { this.Status = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm")} - ERROR. Metadata configured to pull from endpoint with Id {Endpoint.PullMetadataFromEndpointId} but source endpoint not found."; } this.IsRunning = false; continue; } else if (Endpoint.DisableMetadataCapturing) { this.Status = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm")} - Metadata capturing disabled"; this.IsRunning = false; continue; } else if (!Endpoint.IsOrmInstalled) { // try again in 3 seconds this.Status = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm")} - Waiting for ORM to be installed"; Thread.Sleep(3000); continue; } var csb = new SqlConnectionStringBuilder(this.Endpoint.MetadataConnection.ConnectionStringDecrypted); connectionStringRefForLog = $"Data Source={csb.DataSource}; UserId={csb.UserID}; Catalog={csb.InitialCatalog}"; var appName = $"jsdal-server worker {this.Endpoint.Pedigree} {System.Environment.MachineName}"; csb.ApplicationName = appName.Left(128); var connectionStringDecrypted = csb.ToString(); using (var con = new SqlConnection(connectionStringDecrypted)) { try { con.Open(); connectionOpenErrorCnt = 0; } catch (Exception oex) { this.Status = "Failed to open connection to database: " + oex.Message; this.log.Exception(oex, connectionStringRefForLog); connectionOpenErrorCnt++; int waitMS = Math.Min(3000 + (connectionOpenErrorCnt * 3000), 300000 /*Max 5mins between tries*/); this.Status = $"Attempt: #{connectionOpenErrorCnt + 1} (waiting for {waitMS / 1000} secs). " + this.Status; Hubs.WorkerMonitor.Instance.NotifyObservers(); Thread.Sleep(waitMS); continue; } ProcessAsync(con, connectionStringDecrypted).Wait(); } // using connection if (isIterationDirty) { Hubs.WorkerMonitor.Instance.NotifyObservers(); } Thread.Sleep(SettingsInstance.Instance.Settings.DbSource_CheckForChangesInMilliseconds); } catch (Exception ex) { this.log.Exception(ex); exceptionThrottler.Add(DateTime.Now, ex); var thresholdDate = DateTime.Now.AddSeconds(-60); var beforeThreshold = exceptionThrottler.Where(kv => kv.Key < thresholdDate).ToList(); // remove items outside of threshold checking window for (int i = 0; i < beforeThreshold.Count; i++) { exceptionThrottler.Remove(beforeThreshold[i].Key); } // TODO: make threshold count configurable if (exceptionThrottler.Count() >= 6) { exceptionThrottler.Clear(); this.Status = $"{ DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} - Too many exceptions, shutting down thread for now. Last exception: {ex.Message}"; Hubs.WorkerMonitor.Instance.NotifyObservers(); break; // break out of main while loop } this.Status = $"{ DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} - {ex.Message}"; Hubs.WorkerMonitor.Instance.NotifyObservers(); var sleepTimeMS = 2000 + (exceptionThrottler.Count() * 400); // cap at 8 secs sleepTimeMS = sleepTimeMS > 8000 ? 8000 : sleepTimeMS; Thread.Sleep(sleepTimeMS); } } // while IsRunning } catch (ThreadAbortException) { // ignore TAEs } catch (Exception ex) { this.log.Exception(ex); } finally { this.IsRunning = false; this.winThread = null; Hubs.WorkerMonitor.Instance.NotifyObservers(); } } // Run
public static IWebHostBuilder BuildWebHost(string pathToContentRoot, string[] args) { var webServerSettings = SettingsInstance.Instance.Settings.WebServer; // var certPath = "cert.pfx"; // var certPassPath = Path.GetFullPath("cert.pass"); // if (!File.Exists(certPassPath)) // { // throw new Exception($"Unable to find cert path file: {certPassPath}"); // } // var certPass = System.IO.File.ReadAllText(certPassPath); // var configurationBuilder = new ConfigurationBuilder(); // configurationBuilder.AddJsonFile("./appsettings.json", false, true); // var appConfig = configurationBuilder.Build(); return(WebHost .CreateDefaultBuilder(args) .UseSerilog() .UseContentRoot(pathToContentRoot) .UseWebRoot(Path.Combine(pathToContentRoot, "wwwroot")) .UseSetting(WebHostDefaults.SuppressStatusMessagesKey, "true") // .ConfigureAppConfiguration((builderContext, config) => // { // IHostingEnvironment env = builderContext.HostingEnvironment; // config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); // //.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true); // }) .UseHttpSys(options => { options.Authentication.Schemes = AuthenticationSchemes.None; options.Authentication.AllowAnonymous = true; options.MaxConnections = null; options.MaxRequestBodySize = 30000000; //~30MB int interfaceCnt = 0; if ((webServerSettings.EnableSSL ?? false) && !string.IsNullOrWhiteSpace(webServerSettings.HttpsServerHostname) && webServerSettings.HttpsServerPort.HasValue && !string.IsNullOrWhiteSpace(webServerSettings.HttpsCertHash)) { try { var httpsUrl = $"https://{webServerSettings.HttpsServerHostname}:{webServerSettings.HttpsServerPort.Value}"; if (NetshWrapper.ValidateSSLCertBinding(webServerSettings.HttpsServerHostname, webServerSettings.HttpsServerPort.Value)) { if (NetshWrapper.ValidateUrlAcl(true, webServerSettings.HttpsServerHostname, webServerSettings.HttpsServerPort.Value)) { //!eventLog.Info($"Listening to {httpsUrl}"); options.UrlPrefixes.Add(httpsUrl); interfaceCnt++; } else { if (NetshWrapper.AddUrlToACL(true, webServerSettings.HttpsServerHostname, webServerSettings.HttpsServerPort.Value)) { //!eventLog.Info($"Listening to {httpsUrl}"); options.UrlPrefixes.Add(httpsUrl); interfaceCnt++; } else { SessionLog.Error($"The url '{httpsUrl}' was not found in ACL list so a listener for this URL cannot be started."); Log.Error($"The url '{httpsUrl}' was not found in ACL list so a listener for this URL cannot be started."); } } } else { SessionLog.Error($"There is no SSL cert binding for '{httpsUrl}' so a listener for this URL cannot be started."); Log.Error($"There is no SSL cert binding for '{httpsUrl}' so a listener for this URL cannot be started."); } } catch (Exception ex) { SessionLog.Exception(ex); Log.Error(ex, "HTTPS init failed"); } } if (webServerSettings.EnableBasicHttp ?? false) { try { var httpUrl = $"http://{webServerSettings.HttpServerHostname}:{webServerSettings.HttpServerPort}"; if (NetshWrapper.ValidateUrlAcl(false, webServerSettings.HttpServerHostname, webServerSettings.HttpServerPort.Value)) { //!eventLog.Info($"Listening to {httpUrl}"); options.UrlPrefixes.Add(httpUrl); interfaceCnt++; } else { if (NetshWrapper.AddUrlToACL(false, webServerSettings.HttpServerHostname, webServerSettings.HttpServerPort.Value)) { //!eventLog.Info($"Listening to {httpUrl}"); options.UrlPrefixes.Add(httpUrl); interfaceCnt++; } else { SessionLog.Error($"The url '{httpUrl}' was not found in ACL list so a listener for this URL cannot be started."); Log.Error($"The url '{httpUrl}' was not found in ACL list so a listener for this URL cannot be started."); } } } catch (Exception ex) { SessionLog.Exception(ex); Log.Error(ex, "Basic Http init failed"); } } if (interfaceCnt == 0) { Log.Warning("No valid interface (http or https) found so defaulting to localhost:9086"); options.UrlPrefixes.Add("http://localhost:9086"); } }) // .UseKestrel(options => // { // options.AddServerHeader = false; // // TODO: Allow more config here, especially the limits // //!options.Limits.MaxConcurrentConnections // if (webServerSettings.EnableSSL ?? false) // { // if (File.Exists(certPath)) // { // options.Listen(System.Net.IPAddress.Any, webServerSettings.HttpsServerPort ?? 44312, listenOptions => // { // try // { // listenOptions.UseHttps(certPath, certPass); // } // catch (System.Exception ex) // { // SessionLog.Exception(ex); // Cons ole.WriteLine(ex.ToString()); // throw; // } // }); // } // else // { // Cons ole.WriteLine("Cannot start HTTPS listener: The cert file '{0}' does not exists.", certPath); // } // } // if (webServerSettings.EnableBasicHttp ?? false) // { // options.Listen(System.Net.IPAddress.Any, webServerSettings.HttpServerPort ?? 9086); // http // } // }) .UseStartup <Startup>() .UseSetting(WebHostDefaults.DetailedErrorsKey, "true") ); // .UseUrls("http://localhost:9086", "https://*:4430") }
public async Task InitAsync() { // load from plugin directory try { // AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => // { // try // { // var asmName = new AssemblyName(e.Name); // var requestingLocation = e.RequestingAssembly.Location; // var requestingDir = Path.GetDirectoryName(requestingLocation); // // look for a dll in the same location as the requesting assembly // var path = Path.Combine(requestingDir, asmName.Name + ".dll"); // if (!File.Exists(path)) return null; // Assembly.LoadFrom(path); // return null; // } // catch // { // return null; // } // }; var pluginPath = Path.GetFullPath("plugins"); if (Directory.Exists("./plugins")) { var dllCollection = Directory.EnumerateFiles("plugins", "*.dll", SearchOption.TopDirectoryOnly); foreach (var dllPath in dllCollection) { // skip jsdal-plugin base if (dllPath.Equals("plugins\\jsdal-plugin.dll", StringComparison.OrdinalIgnoreCase)) { continue; } try { var ctxName = $"Plugin Context {++_asmCtxCounter}"; var asmCtx = new PluginAssemblyLoadContext(pluginPath, ctxName, true /*enable unloading*/); ASM_CTXES.Add(asmCtx); SessionLog.Info($"Created {ctxName} for {dllPath}".PadRight(35)); var dllFullPath = Path.GetFullPath(dllPath); var pluginAssembly = asmCtx.LoadFromAssemblyPath(dllFullPath); ParseAndLoadPluginAssembly(asmCtx, pluginAssembly, null); } catch (Exception ee) { SessionLog.Error("Failed to load plugin DLL '{0}'. See exception that follows.", dllPath); SessionLog.Exception(ee); } } } } catch (Exception ex) { SessionLog.Exception(ex); } // load inline assemblies try { foreach (var inlineEntry in InlineModuleManifest.Instance.Entries) { var sourcePath = Path.Combine(InlinePluginSourcePath, inlineEntry.Id); if (File.Exists(sourcePath)) { var code = await File.ReadAllTextAsync(sourcePath); CompileCodeIntoAssemblyContext(inlineEntry, code); } else { SessionLog.Error($"Inline module {inlineEntry.Name} not found at '{sourcePath}'"); } } } catch (Exception ex) { SessionLog.Exception(ex); } // init server-wide types // try // { // InitServerWidePlugins(); // } // catch (Exception ex) // { // SessionLog.Exception(ex); // } }
//AssemblyLoadContext, AssemblyName, Assembly? // private Assembly OnResolveAssembly(AssemblyLoadContext ctx, AssemblyName asmName) // { // try // { // // try and find relative to existing assebmlies loaded in ctx // foreach (var asm in ctx.Assemblies) // { // var fi = new FileInfo(asm.Location); // var path = Path.Combine(fi.DirectoryName, asmName.Name + ".dll"); // if (File.Exists(path)) // { // try // { // var loadedAsm = ctx.LoadFromAssemblyPath(path); // if (loadedAsm != null) return loadedAsm; // } // catch { } // } // } // SessionLog.Error($"Failed to resolve {asmName.FullName} in context {ctx.Name}"); // return null; // } // catch // { // return null; // } // } // private Assembly OnResolveAssembly(object sender, ResolveEventArgs e) // { // try // { // var asmName = new AssemblyName(e.Name); // var requestingLocation = e.RequestingAssembly.Location; // var requestingDir = Path.GetDirectoryName(requestingLocation); // // look for a dll in the same location as the requesting assembly // var path = Path.Combine(requestingDir, asmName.Name + ".dll"); // if (!File.Exists(path)) return null; // Assembly.LoadFrom(path); // return null; // } // catch // { // return null; // } // } // private void InitServerWidePlugins() // { // try // { // if (PluginAssemblies == null) return; // foreach (var pluginAssembly in PluginAssemblies) // { // var pluginInfoCollection = pluginAssembly.Plugins.Where(p => p.Type == OM.PluginType.ServerMethod || p.Type == OM.PluginType.BackgroundThread); // foreach (var pluginInfo in pluginInfoCollection) // { // if (pluginInfo.Type == OM.PluginType.BackgroundThread) // { // _backgroundThreadManager.Register(pluginInfo); // } // else if (pluginInfo.Type == OM.PluginType.ServerMethod) // { // ServerMethodManager.Register(pluginAssembly.InstanceId, pluginInfo); // } // } // } // } // catch (Exception ex) // { // SessionLog.Exception(ex); // } // } // parses an Assembly and checks for Plugin-type interface. If found each of those interfaces are tested for validity in terms of mandatory Attribute values and uniqueness private bool ParsePluginAssembly(Assembly pluginAssembly, out List <PluginInfo> pluginInfoList, out List <string> errorList, bool checkForConflict = true) { errorList = new List <string>(); pluginInfoList = new List <PluginInfo>(); if (pluginAssembly.DefinedTypes != null) { var pluginTypeList = pluginAssembly.DefinedTypes.Where(typ => typ.IsSubclassOf(typeof(PluginBase))).ToList(); if (pluginTypeList != null && pluginTypeList.Count > 0) { foreach (var pluginType in pluginTypeList) { var pluginInfo = new PluginInfo(); try { var pluginData = pluginType.GetCustomAttribute(typeof(PluginDataAttribute)) as PluginDataAttribute; if (pluginData == null) { errorList.Add($"Plugin '{pluginType.FullName}' from assembly '{pluginAssembly.FullName}' does not have a PluginData attribute defined on the class level. Add a jsdal_plugin.PluginDataAttribute to the class."); continue; } if (!Guid.TryParse(pluginData.Guid, out var pluginGuid)) { errorList.Add($"Plugin '{pluginType.FullName}' does not have a valid Guid value set on its PluginData attribute."); continue; } if (checkForConflict) { var conflict = PluginAssemblies.SelectMany(a => a.Plugins).FirstOrDefault(p => p.Guid.Equals(pluginGuid)); if (conflict != null) { errorList.Add($"Plugin '{pluginType.FullName}' has a conflicting Guid. The conflict is on assembly {conflict.TypeInfo.FullName} and plugin '{conflict.Name}' with Guid value {conflict.Guid}."); continue; } } if (pluginType.IsSubclassOf(typeof(ExecutionPlugin))) { pluginInfo.Type = OM.PluginType.Execution; } else if (pluginType.IsSubclassOf(typeof(BackgroundThreadPlugin))) { pluginInfo.Type = OM.PluginType.BackgroundThread; } else if (pluginType.IsSubclassOf(typeof(ServerMethodPlugin))) { pluginInfo.Type = OM.PluginType.ServerMethod; // TODO: Additional validation: Look for at least on ServerMethod? otherwise just a warning? // What about unique names of ServerMethods? // Validate Custom Namespace validity (must be JavaScript safe) } else { errorList.Add($"Unknown plugin type '{pluginType.FullName}'."); continue; } pluginInfo.Assembly = pluginAssembly; pluginInfo.Name = pluginData.Name; pluginInfo.Description = pluginData.Description; pluginInfo.TypeInfo = pluginType; pluginInfo.Guid = pluginGuid; //errorList.Add($"Plugin '{pluginInfo.Name}' ({pluginInfo.Guid}) loaded. Assembly: {pluginAssembly.FullName}"); pluginInfoList.Add(pluginInfo); } catch (Exception ex) { errorList.Add("Failed to instantiate type '{pluginType.FullName}'."); errorList.Add(ex.ToString()); SessionLog.Error("Failed to instantiate type '{0}'. See the exception that follows.", pluginType.FullName); SessionLog.Exception(ex); } } } else { errorList.Add($"Failed to find any jsDAL Server plugins in the assembly '{pluginAssembly.Location}'. Make sure you have a public class available that derives from one of the plugin types."); } } else { errorList.Add($"Failed to find any jsDAL Server plugins in the assembly '{pluginAssembly.Location}'. Make sure you have a public class available that derives from one of the plugin types."); } return(errorList == null || errorList.Count == 0); }
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory, IHostApplicationLifetime applicationLifetime) { //app.UseDeveloperExceptionPage(); // force instantiation on singletons { var pmInst = app.ApplicationServices.GetService <PluginLoader>(); CommonNotificationThread.Instance = app.ApplicationServices.GetService <CommonNotificationThread>(); BackgroundThreadPluginManager.Instance = app.ApplicationServices.GetService <BackgroundThreadPluginManager>(); WorkerMonitor.Instance = app.ApplicationServices.GetService <WorkerMonitor>(); RealtimeMonitor.Instance = app.ApplicationServices.GetService <RealtimeMonitor>(); BackgroundTaskMonitor.Instance = app.ApplicationServices.GetService <BackgroundTaskMonitor>(); ConnectionStringSecurity.Instance = app.ApplicationServices.GetService <ConnectionStringSecurity>(); DotNetCoreCounterListener.Instance = app.ApplicationServices.GetService <DotNetCoreCounterListener>(); DotNetCoreCounterListener.Instance.Start(); {// More app startup stuff...but have a dependency on the singleton objects above. Can we move this somewhere else? Log.Information("Initialising project object model"); // we can only initialise the Project structure once ConnectionStringSecurity exists Settings.SettingsInstance.Instance.ProjectList.ForEach(p => p.AfterDeserializationInit()); Log.Information("Initialising plugin loader"); PluginLoader.Instance = pmInst; PluginLoader.Instance.InitAsync().GetAwaiter().GetResult(); ServerMethodManager.RebuildCacheForAllApps(); Log.Information("Starting work spawner."); WorkSpawner.Start(); } } applicationLifetime.ApplicationStopped.Register(() => { Log.Information("Application stopped"); }); applicationLifetime.ApplicationStopping.Register(() => { Log.Information("Application is shutting down"); }); // app.Use(async (httpContext, next) => // { // //if (httpContext.Request.Path.Value.Contains("api/") && httpContext.Request.Method == "OPTIONS") // if (httpContext.Request.Method.Equals("OPTIONS", StringComparison.OrdinalIgnoreCase)) // { // httpContext.Response.Headers.Add("Access-Control-Max-Age", "600"); // // return; // } // await next(); // }); var webSocketOptions = new WebSocketOptions() { KeepAliveInterval = TimeSpan.FromSeconds(120), ReceiveBufferSize = 4 * 1024, }; app.UseWebSockets(webSocketOptions); app.UseCors("CorsPolicy"); // SPA (angular) route fallback app.Use(async(context, next) => { await next(); if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value) && !(context.Request.Path.Value?.ToLower().StartsWith("/api/") ?? false)) { context.Request.Path = "/index.html"; context.Response.StatusCode = 200; await next(); } }); /***** * var mirrorSharpOptions = new MirrorSharpOptions() * { * SelfDebugEnabled = true, * IncludeExceptionDetails = true, * //SetOptionsFromClient = SetOptionsFromClientExtension() * // CSharp = { * // MetadataReferences = ImmutableList.Create<MetadataReference>(all), * // CompilationOptions = compilationOptions * // }, * ExceptionLogger = new MirrorSharpExceptionLogger() * }.SetupCSharp(cs => * { * //cs.MetadataReferences = cs.MetadataReferences.Clear(); * //cs.AddMetadataReferencesFromFiles(all); * cs.MetadataReferences = ImmutableList.Create<MetadataReference>(all); * cs.CompilationOptions = compilationOptions; * * }); * * * app.UseMirrorSharp(mirrorSharpOptions); */ app.UseDefaultFiles(); app.UseStaticFiles(); // TODO: This outputs full request detail into log. Perhaps consider outputting this to a different detailed log //app.UseSerilogRequestLogging(); app.UseSerilogRequestLogging(options => { options.GetType().GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); // Customize the message template //HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms options.MessageTemplate = "Req/Res: {ReqLen,7} {ResLen,7} {StatusCode} {Elapsed,7:0} ms {RequestMethod,4} {RequestPath}"; //options.GetLevel = (httpContext, elapsed, ex) => Serilog.Events.LogEventLevel.Warning; // Attach additional properties to the request completion event options.EnrichDiagnosticContext = (diagnosticContext, httpContext) => { diagnosticContext.Set("ResLen", httpContext.Response.ContentLength ?? 0); diagnosticContext.Set("ReqLen", httpContext.Request.ContentLength ?? 0); }; }); app.UseRouting(); MetadataReference[] allMetadataReferences = null; try { allMetadataReferences = CSharpCompilerHelper.GetCommonMetadataReferences(); var jsDALBasePluginPath = Path.GetFullPath("./plugins/jsdal-plugin.dll"); if (File.Exists("./plugins/jsdal-plugin.dll")) { Array.Resize(ref allMetadataReferences, allMetadataReferences.Length + 1); allMetadataReferences[allMetadataReferences.Length - 1] = Microsoft.CodeAnalysis.MetadataReference.CreateFromFile(jsDALBasePluginPath); } else { Log.Error($"Failed to find base plugin assembly at {jsDALBasePluginPath}"); SessionLog.Error($"Failed to find base plugin assembly at {jsDALBasePluginPath}"); } } catch (Exception mex) { Log.Error(mex, "Failed to compile collection of metadata references"); } app.UseEndpoints(endpoints => { endpoints.MapHub <Hubs.HomeDashboardHub>("/main-stats"); endpoints.MapHub <Hubs.WorkerDashboardHub>("/worker-hub"); endpoints.MapHub <Hubs.Performance.RealtimeHub>("/performance-realtime-hub"); endpoints.MapHub <Hubs.HeartBeat.HeartBeatHub>("/heartbeat"); endpoints.MapHub <Hubs.BackgroundTaskHub>("/bgtasks-hub"); endpoints.MapHub <Hubs.BackgroundPluginHub>("/bgplugin-hub"); endpoints.MapHub <Hubs.ExecHub>("/exec-hub"); if (allMetadataReferences?.Length > 0) { var compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, // generalDiagnosticOption: ReportDiagnostic.Suppress specificDiagnosticOptions: new Dictionary <string, ReportDiagnostic> { { "CS1701", ReportDiagnostic.Suppress }, // Binding redirects { "CS1702", ReportDiagnostic.Suppress }, { "CS1705", ReportDiagnostic.Suppress } } ); var mirrorSharpOptions = new MirrorSharpOptions() { SelfDebugEnabled = true, IncludeExceptionDetails = true //SetOptionsFromClient = SetOptionsFromClientExtension() // CSharp = { // MetadataReferences = ImmutableList.Create<MetadataReference>(all), // CompilationOptions = compilationOptions // }, // ExceptionLogger = new MirrorSharpExceptionLogger() }.SetupCSharp(cs => { //cs.MetadataReferences = cs.MetadataReferences.Clear(); //cs.AddMetadataReferencesFromFiles(all); cs.MetadataReferences = ImmutableList.Create <MetadataReference>(allMetadataReferences); cs.CompilationOptions = compilationOptions; }); endpoints.MapMirrorSharp("/mirrorsharp", mirrorSharpOptions); } else { Log.Warning("Mirrorsharp not started because of errors builiding up metadata references"); } }); app.UseAuthentication(); app.UseWebSockets(); app.UseCookiePolicy(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseHsts(); // unhandled exceptions app.UseExceptionHandler(errorApp => { errorApp.Run(async context => { try { var exceptionHandlerPathFeature = context.Features.Get <IExceptionHandlerPathFeature>(); var id = ExceptionLogger.LogException(exceptionHandlerPathFeature.Error, exceptionHandlerPathFeature.Path, "jsdal-server", null); context.Response.StatusCode = 500; context.Response.ContentType = "text/plain"; await context.Response.WriteAsync($"Server error. Ref: {id}"); await context.Response.WriteAsync(new string(' ', 512)); // IE padding } catch (Exception ex) { Log.Error(ex, $"Failed to log unhandled exception because of:\r\n {ex.ToString()}"); } }); }); } app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); }