Example #1
0
        /// <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
        }