/// <summary> /// Assembles all needed components for the application and performs the <paramref name="applicationCode"/> function. /// <para> /// <list type="number"> /// <item>It builds <see cref="JsonConfiguration"/> using either <paramref name="customConfigurationFilePaths"/>, if they /// are not empty, or files <see cref="DefaultConfigurationFilePath"/> and <see cref="DevConfigurationFilePath"/>.</item> /// <item>Sets up Serilog logging using <see cref="LoggingUtilities.SetupSerilog(JsonConfiguration)"/>.</item> /// <item>Constructs an empty Ninject kernel using <see cref="NinjectUtilities.CreateKernel"/>.</item> /// <item>Runs the <paramref name="applicationCode"/> and logs its exceptions.</item> /// </list> /// </para> /// </summary> /// <param name="customConfigurationFilePaths">The paths to custom configuration files loaded in this order. If no files are /// specified, then the files <see cref="DefaultConfigurationFilePath"/> and <see cref="DevConfigurationFilePath"/> are used.</param> /// <param name="applicationCode">The function performing the actual application code.</param> public static async Task Run(string[] customConfigurationFilePaths, Func <IKernel, JsonConfiguration, Task> applicationCode) { #region Load JsonConfiguration // Prepare the variable for settings JsonConfiguration jsonConfiguration; try { // If the custom files are specified... jsonConfiguration = customConfigurationFilePaths.Length != 0 // Load the configuration from them ? new JsonConfiguration(customConfigurationFilePaths) // Otherwise use the default files : new JsonConfiguration(DefaultConfigurationFilePath, DevConfigurationFilePath); } catch (Exception e) { // Re-throw throw new ConfigurationException($"Cannot set up a JsonConfiguration from arguments: {customConfigurationFilePaths.ToJoinedString()}", e); } #endregion #region Logging try { // Ensure we have logging LoggingUtilities.SetupSerilog(jsonConfiguration); } catch (Exception e) { // Re-throw throw new LoggingException($"Cannot set up Serilog using the configuration loaded from {customConfigurationFilePaths.ToJoinedString()}", e); } #endregion #region Application Code try { // Log start Log.Information("The application has started."); // Log from where we have the configuration from Log.Information("Configuration loaded from files: {files}", jsonConfiguration.LoadedConfigurationFilePaths.ToJoinedString()); // Prepare a stopwatch var stopwatch = Stopwatch.StartNew(); // Execute the application code with a new empty kernel await applicationCode(NinjectUtilities.CreateKernel(), jsonConfiguration); // Log end Log.Information("The application has finished correctly in {time:F2} sec.\n", stopwatch.ElapsedMilliseconds / 1000d); } // Catch for any unhandled exception catch (Exception e) { // Log if there is any Log.Fatal(e, $"An unexpected exception has occurred."); // This is a sad end throw; } #endregion }