Пример #1
0
        public void AddPlugin(PluginInfo plugin)
        {
            try
            {
                this._plugins.Add(plugin);

                if (plugin.Type == PluginType.BackgroundThread)
                {
                    BackgroundThreadPluginManager.Instance.Register(plugin);
                }
                else if (plugin.Type == PluginType.ServerMethod)
                {
                    ServerMethodManager.Register(InstanceId, plugin);
                }
            }
            catch (Exception ex)
            {
                SessionLog.Exception(ex);
            }
        }
Пример #2
0
        public void BuildAndCacheServerMethodJsAndTSD()
        {
            try
            {
                var registrations = ServerMethodManager.GetRegistrationsForApp(this);

                if (registrations.Count() > 0)
                {
                    this.GenerateX(registrations);
                }
                else
                {
                    this.ServerMethodJs = this.ServerMethodTSD = this.ServerMethodJsEtag = this.ServerMethodTSDEtag = null;
                }
            }
            catch (Exception ex)
            {
                SessionLog.Error($"Failed to generate ServerMethod output files for {this.Project.Name}/{this.Name}.See exception that follows.");
                SessionLog.Exception(ex);
            }
        }
Пример #3
0
        public bool LoadOrUpdateInlineAssembly(InlineModuleManifestEntry inlineEntry, string code, out List <string> errorList)
        {
            errorList = null;

            var existingPluginAssembly = this.PluginAssemblies.FirstOrDefault(p => p.InlineEntryId != null &&
                                                                              p.InlineEntryId.Equals(inlineEntry.Id, StringComparison.Ordinal) && p.IsInline);

            if (existingPluginAssembly != null)
            {
                var existingAsmCtx = AssemblyLoadContext.GetLoadContext(existingPluginAssembly.Assembly);
                // unload existing PluginAssembly
                existingPluginAssembly.Unload();

                this._pluginAssemblies.Remove(existingPluginAssembly);

                Instance.CompileCodeIntoAssemblyContext(inlineEntry, code);

                // if (!ParsePluginAssembly(newAssembly, out var pluginInfoList, out errorList, checkForConflict: false))
                // {
                //     return false;
                // }

                //existingPluginAssembly.UpdatePluginList(pluginInfoList);
                //SessionLog.Info($"Assembly {existingPluginAssembly.Assembly.FullName} updated");
            }
            else
            {
                // new?
                Instance.CompileCodeIntoAssemblyContext(inlineEntry, code);
            }



            // TODO: Perhaps this can be optimised to run only on apps that are affected by plugin change
            ServerMethodManager.RebuildCacheForAllApps();


            return(true);
        }
Пример #4
0
        // public void UpdatePluginList(List<PluginInfo> list)
        // {
        //     this._plugins.Clear();
        //     this._plugins.AddRange(list);
        // }

        public void Unload()
        {
            var serverMethodPlugins = _plugins.Where(pi => pi.Type == PluginType.ServerMethod);

            if (serverMethodPlugins.Count() > 0)
            {
                // TODO: remove from SM manager entirely??!?!?!
                ServerMethodManager.HandleAssemblyUpdated(InstanceId, serverMethodPlugins.ToList());
            }

            var bgThreadPlugins = _plugins.Where(pi => pi.Type == PluginType.BackgroundThread).ToList();

            if (bgThreadPlugins.Count() > 0)
            {
                BackgroundThreadPluginManager.Instance.StopAll(bgThreadPlugins);
            }

            this._plugins.Clear();
            this.AssemblyLoadContext.Unload();
            this.InlineEntryId       = null;
            this.Assembly            = null;
            this.AssemblyLoadContext = null;
        }
Пример #5
0
        public CommonReturnValue UpdatePluginList(dynamic pluginList)
        {
            var oldList = this.Plugins;

            if (oldList == null)
            {
                oldList = new List <string>();
            }

            this.Plugins = new List <string>();

            if (pluginList == null)
            {
                return(CommonReturnValue.Success());
            }

            foreach (Newtonsoft.Json.Linq.JObject p in pluginList)
            {
                bool included = (bool)p["Included"];
                Guid g        = (Guid)p["Guid"];

                if (included)
                {
                    this.Plugins.Add(g.ToString());
                }
            }
            ;

            var newlyEnabled = this.Plugins.Where(p => oldList.FirstOrDefault(x => x.Equals(p, StringComparison.OrdinalIgnoreCase)) == null).Select(g => g.ToLower());
            var disabled     = oldList.Where(p => this.Plugins.FirstOrDefault(x => x.Equals(p, StringComparison.OrdinalIgnoreCase)) == null).Select(g => g.ToLower());

            var ret = PluginLoader.Instance.PluginAssemblies
                      .SelectMany(a => a.Plugins, (pa, plugin) => new
            {
                PluginAssembly = pa,
                PluginInfo     = plugin
            })
                      .Where(p => p.PluginInfo.Type == PluginType.BackgroundThread || p.PluginInfo.Type == PluginType.ServerMethod)
                      .ToList();

            var startList = ret.Where(p => newlyEnabled.Contains(p.PluginInfo.Guid.ToString().ToLower()));
            var stopList  = ret.Where(p => disabled.Contains(p.PluginInfo.Guid.ToString().ToLower()));

            // START
            {
                foreach (var item in startList)
                {
                    if (item.PluginInfo.Type == PluginType.BackgroundThread)
                    {
                        BackgroundThreadPluginManager.Instance.Register(item.PluginInfo);
                    }
                    else if (item.PluginInfo.Type == PluginType.ServerMethod)
                    {
                        ServerMethodManager.Register(item.PluginAssembly.InstanceId, item.PluginInfo);
                    }
                }
            }

            // STOP
            {
                foreach (var item in stopList)
                {
                    if (item.PluginInfo.Type == PluginType.BackgroundThread)
                    {
                        // TODO: Implement a stop and call for specific EP!
                        BackgroundThreadPluginManager.Instance.StopForApp(this, item.PluginInfo);
                        //BackgroundThreadPluginManager.Instance.Register(item.PluginInfo);
                    }
                    else if (item.PluginInfo.Type == PluginType.ServerMethod)
                    {
                        //ServerMethodManager.Register(item.PluginAssembly.InstanceId, item.PluginInfo);
                    }
                }
            }

            return(CommonReturnValue.Success());
        }
Пример #6
0
        public (plugin.ServerMethodPlugin, ServerMethodRegistrationMethod /*matched Method*/, string /*error*/) GetServerMethodPluginInstance(string nameSpace,
                                                                                                                                              string methodName, Dictionary <string, string> inputParameters)
        {
            // find all registered ServerMethods for this app
            var registrations = ServerMethodManager.GetRegistrationsForApp(this.Application);

            // TODO: To support overloading we need to match name + best fit parameter list
            var methodCandidates = registrations.SelectMany(reg => reg.Methods)
                                   .Where(m => ((nameSpace == null && m.Namespace == null) || (m.Namespace?.Equals(nameSpace, StringComparison.Ordinal) ?? false)) && m.Name.Equals(methodName, StringComparison.Ordinal))
                                   .Select(m => m);

            if (methodCandidates.Count() == 0)
            {
                return(null, null, "Method name not found.");
            }

            var weightedMethodList = new List <(decimal /*weight*/, string /*error*/, ServerMethodRegistrationMethod)>();

            // find the best matching overload (if any)
            foreach (var regMethod in methodCandidates)
            {
                var methodParameters = regMethod.AssemblyMethodInfo.GetParameters();

                if (inputParameters.Count > methodParameters.Length)
                {
                    weightedMethodList.Add((1M, "Too many parameters specified", regMethod));
                    continue;
                }

                var joined = from methodParam in methodParameters
                             join inputParam in inputParameters on methodParam.Name equals inputParam.Key into grp
                             from parm in grp.DefaultIfEmpty()
                             select new { HasMatch = parm.Key != null, Param = methodParam };

                var matched    = joined.Where(e => e.HasMatch);
                var notmatched = joined.Where(e => !e.HasMatch);


                var expectedCnt = methodParameters.Count();
                var matchedCnt  = matched.Count();

                // out/ref/optional parameters are added as extra credit below (but does not contribute to actual weight)
                var outRefSum = (from p in joined
                                 where (p.Param.IsOut || p.Param.IsOptional || p.Param.ParameterType.IsByRef) && !p.HasMatch
                                 select 1.0M).Sum();


                if (matchedCnt == expectedCnt || matchedCnt + outRefSum == expectedCnt)
                {
                    weightedMethodList.Add((matchedCnt, null, regMethod));
                }
                else
                {
                    //weightedMethodList.Add((matchedCnt, $"Following parameters not specified: {string.Join("\r\n", notmatched.Select(nm => nm.Param.Name))}", regMethod));
                    weightedMethodList.Add((matchedCnt, "Parameter mismatch", regMethod));
                }
            }

            var bestMatch = weightedMethodList.OrderByDescending(k => k.Item1).FirstOrDefault();

            if (!string.IsNullOrWhiteSpace(bestMatch.Item2))
            {
                var parms    = bestMatch.Item3.AssemblyMethodInfo.GetParameters();
                var parmDesc = "(no parameters)";
                if (parms.Length > 0)
                {
                    parmDesc = string.Join("\r\n", parms.Select(p => $"{p.Name} ({p.ParameterType.ToString()})")); // TODO: Provide "easy to read" description for type, e.g. nullabe Int32 can be something like 'int?' and 'List<string>' just 'string[]'
                }

                return(null, bestMatch.Item3, $"Failed to find suitable overload.\r\nError: {bestMatch.Item2}\r\nBest match requires parameters:\r\n{parmDesc}");
            }

            var matchedRegMethod = bestMatch.Item3;

            var cacheKey = $"{matchedRegMethod.Registration.PluginAssemblyInstanceId}; {matchedRegMethod.Registration.TypeInfo.FullName}";

            plugin.ServerMethodPlugin pluginInstance = null;

            lock (ServerMethodInstanceCache)
            {
                if (ServerMethodInstanceCache.ContainsKey(cacheKey))
                {
                    pluginInstance = ServerMethodInstanceCache[cacheKey];
                }
                else // instantiate a new instance
                {
                    try
                    {
                        pluginInstance = (plugin.ServerMethodPlugin)matchedRegMethod.Registration.Assembly.CreateInstance(matchedRegMethod.Registration.TypeInfo.FullName);
                        var initMethod = typeof(plugin.ServerMethodPlugin).GetMethod("InitSM", BindingFlags.Instance | BindingFlags.NonPublic);

                        if (initMethod != null)
                        {
                            initMethod.Invoke(pluginInstance, new object[] {
                                new Func <SqlConnection>(() => {
                                    if (this.ExecutionConnection != null)
                                    {
                                        var con = new SqlConnection(this.ExecutionConnection.ConnectionStringDecrypted);

                                        con.Open();

                                        return(con);
                                    }

                                    return(new SqlConnection());
                                })
                            });
                        }
                        else
                        {
                            SessionLog.Warning($"Failed to find InitSM method on plugin {matchedRegMethod.Registration.TypeInfo.FullName} from assembly {matchedRegMethod.Registration.Assembly.FullName}. Make sure the correct version of the jsdal plugin is used and that you derive from the correct base class (should be ServerMethodPlugin).");
                        }

                        var setGetServicesFuncMethod = typeof(plugin.PluginBase).GetMethod("SetGetServicesFunc", BindingFlags.Instance | BindingFlags.NonPublic);

                        if (setGetServicesFuncMethod != null)
                        {
                            setGetServicesFuncMethod.Invoke(pluginInstance, new object[] { new Func <Type, plugin.PluginService>(serviceType =>
                                {
                                    if (serviceType == typeof(plugin.BlobStoreBase))
                                    {
                                        return(BlobStore.Instance);
                                    }

                                    return(null);
                                }) });
                        }

                        ServerMethodManager.RegisterInstanceUse(this, matchedRegMethod);
                        ServerMethodInstanceCache.Add(cacheKey, pluginInstance);
                    }
                    catch (Exception ex)
                    {
                        SessionLog.Error($"Failed to instantiate plugin {matchedRegMethod.Registration.TypeInfo.FullName} from assembly {matchedRegMethod.Registration.Assembly.FullName}. See exception that follows.");
                        SessionLog.Exception(ex);
                    }
                }
            } // lock

            return(pluginInstance, matchedRegMethod, null);
        }
Пример #7
0
        // look for all supported types of plugins and validate
        public static bool ParsePluginSource(string existingId, string code, out List <BasePluginRuntime> parsedPlugins, out List <string> problems)
        {
            problems      = new List <string>();
            parsedPlugins = new List <BasePluginRuntime>();

            try
            {
                var allPluginTypes         = new Type[] { typeof(jsdal_plugin.ServerMethodPlugin), typeof(jsdal_plugin.ExecutionPlugin), typeof(jsdal_plugin.BackgroundThreadPlugin) };
                var allPluginTypeFullNames = from t in allPluginTypes select t.FullName;

                var tree        = CSharpSyntaxTree.ParseText(code);
                var compilation = CSharpCompilation.Create("TmpAsm", syntaxTrees: new[] { tree }, references: GetCommonMetadataReferences());
                var model       = compilation.GetSemanticModel(tree);
                var root        = model.SyntaxTree.GetRoot();

                // get a list of all supported Plugin classes
                var pluginClasses = root
                                    .DescendantNodes()
                                    .OfType <ClassDeclarationSyntax>()
                                    .Select(cls => new { ClassDeclaration = cls, Symbol = model.GetDeclaredSymbol(cls) })
                                    .Where(cls => allPluginTypeFullNames.Contains(cls.Symbol.BaseType.ToString()))
                                    //.Where(cls => cls.Symbol.BaseType.ToString() == typeof(BasePluginRuntime).FullName)
                                    .ToList()
                ;

                if (pluginClasses.Count == 0)
                {
                    problems.Add($"You need to have at least one type that inherits from on of the following: {string.Join(", ", allPluginTypeFullNames)}.");
                    return(false);
                }

                foreach (var pc in pluginClasses)
                {
                    var pluginDataAttrib = pc.Symbol.GetAttributes().FirstOrDefault(a => a.AttributeConstructor?.ContainingType?
                                                                                    .ConstructedFrom?
                                                                                    .ToDisplayString()
                                                                                    .Equals("jsdal_plugin.PluginDataAttribute", StringComparison.OrdinalIgnoreCase) ?? false);

                    if (pluginDataAttrib != null)
                    {
                        if (pluginDataAttrib.ConstructorArguments.Length == 0)
                        {
                            problems.Add($"Type '{pc.Symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}' has a PluginData attribute with no value. Please provide a valid GUID value.");
                        }
                        else
                        {
                            var namePart = pluginDataAttrib.ConstructorArguments[0];
                            var guidPart = pluginDataAttrib.ConstructorArguments[1];
                            var descPart = pluginDataAttrib.ConstructorArguments[2];

                            var newParsedPlugin = new BasePluginRuntime();

                            parsedPlugins.Add(newParsedPlugin);

                            if (namePart.IsNull || string.IsNullOrWhiteSpace(namePart.Value.ToString()))
                            {
                                problems.Add($"Type '{pc.Symbol.ToDisplayString()}' has a PluginData attribute with a null or empty Name value.");
                            }
                            else
                            {
                                newParsedPlugin.Name = namePart.Value.ToString();
                            }

                            if (guidPart.IsNull || string.IsNullOrWhiteSpace(guidPart.Value.ToString()) || !Guid.TryParse(guidPart.Value.ToString(), out var gg) || gg == Guid.Empty)
                            {
                                problems.Add($"Type '{pc.Symbol.ToDisplayString()}' has a PluginData attribute with an invalid Guid value.");
                            }
                            else
                            {
                                newParsedPlugin.PluginGuid = gg.ToString().ToLower();
                            }

                            if (!descPart.IsNull)
                            {
                                newParsedPlugin.Description = descPart.Value.ToString();
                                if (string.IsNullOrWhiteSpace(newParsedPlugin.Description))
                                {
                                    newParsedPlugin.Description = null;
                                }
                            }

                            // if adding a new module
                            if (existingId == null || existingId.Equals("new", StringComparison.OrdinalIgnoreCase))
                            {
                                var existing = ServerMethodManager
                                               .GetRegistrationByPluginGuid(newParsedPlugin.PluginGuid);

                                if (existing != null)
                                {
                                    problems.Add($"The type '{pc.Symbol.ToDisplayString()}' has a Plugin Guid that conflicts with an existing loaded plugin. The conflict occurred with '{existing.TypeInfo.FullName}'.");
                                }
                            }
                        }
                    }
                    else
                    {
                        problems.Add($"The type '{pc.Symbol.ToDisplayString()}' is missing a PluginData attribute declaration.");
                    }
                }

                return(problems.Count == 0);
            }
            catch (CompilationErrorException ce)
            {
                problems.Add("Compilation errors.");

                foreach (var d in ce.Diagnostics)
                {
                    problems.Add(d.GetMessage());
                }

                return(false);
            }
        }
Пример #8
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?}");
            });
        }