diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index d51e74a4de..3d79cae1e5 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -325,8 +325,6 @@ namespace Emby.Server.Implementations
private IMediaSourceManager MediaSourceManager { get; set; }
- private readonly IConfiguration _configuration;
-
///
/// Gets the installation manager.
///
@@ -364,11 +362,8 @@ namespace Emby.Server.Implementations
IStartupOptions options,
IFileSystem fileSystem,
IImageEncoder imageEncoder,
- INetworkManager networkManager,
- IConfiguration configuration)
+ INetworkManager networkManager)
{
- _configuration = configuration;
-
XmlSerializer = new MyXmlSerializer();
NetworkManager = networkManager;
@@ -584,7 +579,8 @@ namespace Emby.Server.Implementations
}
}
- public async Task InitAsync(IServiceCollection serviceCollection)
+ ///
+ public async Task InitAsync(IServiceCollection serviceCollection, IConfiguration startupConfig)
{
HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber;
HttpsPort = ServerConfigurationManager.Configuration.HttpsPortNumber;
@@ -617,7 +613,7 @@ namespace Emby.Server.Implementations
DiscoverTypes();
- await RegisterResources(serviceCollection).ConfigureAwait(false);
+ await RegisterResources(serviceCollection, startupConfig).ConfigureAwait(false);
ContentRoot = ServerConfigurationManager.Configuration.DashboardSourcePath;
if (string.IsNullOrEmpty(ContentRoot))
@@ -656,7 +652,7 @@ namespace Emby.Server.Implementations
///
/// Registers resources that classes will depend on
///
- protected async Task RegisterResources(IServiceCollection serviceCollection)
+ protected async Task RegisterResources(IServiceCollection serviceCollection, IConfiguration startupConfig)
{
serviceCollection.AddMemoryCache();
@@ -665,8 +661,6 @@ namespace Emby.Server.Implementations
serviceCollection.AddSingleton(ApplicationPaths);
- serviceCollection.AddSingleton(_configuration);
-
serviceCollection.AddSingleton(JsonSerializer);
// TODO: Support for injecting ILogger should be deprecated in favour of ILogger and this removed
@@ -758,7 +752,7 @@ namespace Emby.Server.Implementations
ProcessFactory,
LocalizationManager,
() => SubtitleEncoder,
- _configuration,
+ startupConfig,
StartupOptions.FFmpegPath);
serviceCollection.AddSingleton(MediaEncoder);
@@ -780,7 +774,7 @@ namespace Emby.Server.Implementations
this,
LoggerFactory.CreateLogger(),
ServerConfigurationManager,
- _configuration,
+ startupConfig,
NetworkManager,
JsonSerializer,
XmlSerializer,
diff --git a/Jellyfin.Server/CoreAppHost.cs b/Jellyfin.Server/CoreAppHost.cs
index 8b4b61e290..ed5968ad6f 100644
--- a/Jellyfin.Server/CoreAppHost.cs
+++ b/Jellyfin.Server/CoreAppHost.cs
@@ -23,23 +23,20 @@ namespace Jellyfin.Server
/// The to be used by the .
/// The to be used by the .
/// The to be used by the .
- /// The to be used by the .
public CoreAppHost(
ServerApplicationPaths applicationPaths,
ILoggerFactory loggerFactory,
StartupOptions options,
IFileSystem fileSystem,
IImageEncoder imageEncoder,
- INetworkManager networkManager,
- IConfiguration configuration)
+ INetworkManager networkManager)
: base(
applicationPaths,
loggerFactory,
options,
fileSystem,
imageEncoder,
- networkManager,
- configuration)
+ networkManager)
{
}
diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs
index 7c3d0f2771..e9e852349c 100644
--- a/Jellyfin.Server/Program.cs
+++ b/Jellyfin.Server/Program.cs
@@ -112,10 +112,12 @@ namespace Jellyfin.Server
// $JELLYFIN_LOG_DIR needs to be set for the logger configuration manager
Environment.SetEnvironmentVariable("JELLYFIN_LOG_DIR", appPaths.LogDirectoryPath);
- IConfiguration appConfig = await CreateConfiguration(appPaths).ConfigureAwait(false);
-
- CreateLogger(appConfig, appPaths);
+ // Create an instance of the application configuration to use for application startup
+ await InitLoggingConfigFile(appPaths).ConfigureAwait(false);
+ IConfiguration startupConfig = CreateAppConfiguration(appPaths);
+ // Initialize logging framework
+ InitializeLoggingFramework(startupConfig, appPaths);
_logger = _loggerFactory.CreateLogger("Main");
// Log uncaught exceptions to the logging instead of std error
@@ -180,23 +182,22 @@ namespace Jellyfin.Server
options,
new ManagedFileSystem(_loggerFactory.CreateLogger(), appPaths),
GetImageEncoder(appPaths),
- new NetworkManager(_loggerFactory.CreateLogger()),
- appConfig);
+ new NetworkManager(_loggerFactory.CreateLogger()));
try
{
ServiceCollection serviceCollection = new ServiceCollection();
- await appHost.InitAsync(serviceCollection).ConfigureAwait(false);
+ await appHost.InitAsync(serviceCollection, startupConfig).ConfigureAwait(false);
- var host = CreateWebHostBuilder(appHost, serviceCollection).Build();
+ var webHost = CreateWebHostBuilder(appHost, serviceCollection, appPaths).Build();
// A bit hacky to re-use service provider since ASP.NET doesn't allow a custom service collection.
- appHost.ServiceProvider = host.Services;
+ appHost.ServiceProvider = webHost.Services;
appHost.FindParts();
Migrations.MigrationRunner.Run(appHost, _loggerFactory);
try
{
- await host.StartAsync().ConfigureAwait(false);
+ await webHost.StartAsync().ConfigureAwait(false);
}
catch
{
@@ -232,7 +233,7 @@ namespace Jellyfin.Server
}
}
- private static IWebHostBuilder CreateWebHostBuilder(ApplicationHost appHost, IServiceCollection serviceCollection)
+ private static IWebHostBuilder CreateWebHostBuilder(ApplicationHost appHost, IServiceCollection serviceCollection, IApplicationPaths appPaths)
{
return new WebHostBuilder()
.UseKestrel(options =>
@@ -272,6 +273,7 @@ namespace Jellyfin.Server
}
}
})
+ .ConfigureAppConfiguration(config => config.ConfigureAppConfiguration(appPaths))
.UseSerilog()
.UseContentRoot(appHost.ContentRoot)
.ConfigureServices(services =>
@@ -445,38 +447,51 @@ namespace Jellyfin.Server
return new ServerApplicationPaths(dataDir, logDir, configDir, cacheDir, webDir);
}
- private static async Task CreateConfiguration(IApplicationPaths appPaths)
+ ///
+ /// Initialize the logging configuration file using the bundled resource file as a default if it doesn't exist
+ /// already.
+ ///
+ private static async Task InitLoggingConfigFile(IApplicationPaths appPaths)
{
- const string ResourcePath = "Jellyfin.Server.Resources.Configuration.logging.json";
+ // Do nothing if the config file already exists
string configPath = Path.Combine(appPaths.ConfigurationDirectoryPath, LoggingConfigFileDefault);
-
- if (!File.Exists(configPath))
+ if (File.Exists(configPath))
{
- // For some reason the csproj name is used instead of the assembly name
- await using Stream? resource = typeof(Program).Assembly.GetManifestResourceStream(ResourcePath);
- if (resource == null)
- {
- throw new InvalidOperationException(
- string.Format(
- CultureInfo.InvariantCulture,
- "Invalid resource path: '{0}'",
- ResourcePath));
- }
-
- await using Stream dst = File.Open(configPath, FileMode.CreateNew);
- await resource.CopyToAsync(dst).ConfigureAwait(false);
+ return;
}
+ // Get a stream of the resource contents
+ // NOTE: The .csproj name is used instead of the assembly name in the resource path
+ const string ResourcePath = "Jellyfin.Server.Resources.Configuration.logging.json";
+ await using Stream? resource = typeof(Program).Assembly.GetManifestResourceStream(ResourcePath)
+ ?? throw new InvalidOperationException($"Invalid resource path: '{ResourcePath}'");
+
+ // Copy the resource contents to the expected file path for the config file
+ await using Stream dst = File.Open(configPath, FileMode.CreateNew);
+ await resource.CopyToAsync(dst).ConfigureAwait(false);
+ }
+
+ private static IConfiguration CreateAppConfiguration(IApplicationPaths appPaths)
+ {
return new ConfigurationBuilder()
+ .ConfigureAppConfiguration(appPaths)
+ .Build();
+ }
+
+ private static IConfigurationBuilder ConfigureAppConfiguration(this IConfigurationBuilder config, IApplicationPaths appPaths)
+ {
+ return config
.SetBasePath(appPaths.ConfigurationDirectoryPath)
.AddInMemoryCollection(ConfigurationOptions.Configuration)
.AddJsonFile(LoggingConfigFileDefault, optional: false, reloadOnChange: true)
.AddJsonFile(LoggingConfigFileSystem, optional: true, reloadOnChange: true)
- .AddEnvironmentVariables("JELLYFIN_")
- .Build();
+ .AddEnvironmentVariables("JELLYFIN_");
}
- private static void CreateLogger(IConfiguration configuration, IApplicationPaths appPaths)
+ ///
+ /// Initialize Serilog using configuration and fall back to defaults on failure.
+ ///
+ private static void InitializeLoggingFramework(IConfiguration configuration, IApplicationPaths appPaths)
{
try
{
diff --git a/MediaBrowser.Common/IApplicationHost.cs b/MediaBrowser.Common/IApplicationHost.cs
index 68a24aabaa..0e282cf538 100644
--- a/MediaBrowser.Common/IApplicationHost.cs
+++ b/MediaBrowser.Common/IApplicationHost.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Model.Updates;
+using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace MediaBrowser.Common
@@ -121,11 +122,12 @@ namespace MediaBrowser.Common
void RemovePlugin(IPlugin plugin);
///
- /// Inits this instance.
+ /// Initializes this instance.
///
/// The service collection.
+ /// The configuration to use for initialization.
/// A task.
- Task InitAsync(IServiceCollection serviceCollection);
+ Task InitAsync(IServiceCollection serviceCollection, IConfiguration startupConfig);
///
/// Creates the instance.
diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj
index 3da8644040..04e0ee67a2 100644
--- a/MediaBrowser.Common/MediaBrowser.Common.csproj
+++ b/MediaBrowser.Common/MediaBrowser.Common.csproj
@@ -12,6 +12,7 @@
+