Port remaining C# to .NET Core 3.1

- Add IDatabaseCollection for abstracting DbSet.
This commit is contained in:
Cyberboss
2020-04-18 22:56:35 -04:00
parent 28e3eb4ba0
commit 82e283141e
18 changed files with 349 additions and 124 deletions
@@ -2,7 +2,7 @@
<Import Project="../../build/Version.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netstandard2.1</TargetFramework>
<DebugType>Full</DebugType>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Authors>Cyberboss</Authors>
@@ -2,7 +2,7 @@
<Import Project="../../build/Version.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netstandard2.1</TargetFramework>
<DebugType>Full</DebugType>
<Version>$(TgsClientVersion)</Version>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
@@ -3,7 +3,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net471</TargetFramework>
<TargetFramework>net472</TargetFramework>
<RuntimeIdentifier>win</RuntimeIdentifier>
<DebugType>Full</DebugType>
<Version>$(TgsCoreVersion)</Version>
@@ -80,6 +80,7 @@ namespace Tgstation.Server.Host.Controllers
var revisionInfo = await ApplyQuery(databaseContext.RevisionInformations).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
// If the DB doesn't have it, check the local set
if (revisionInfo == default)
revisionInfo = databaseContext.RevisionInformations.Local.Where(x => x.CommitSha == repoSha && x.Instance.Id == instance.Id).FirstOrDefault();
@@ -669,6 +670,7 @@ namespace Tgstation.Server.Host.Controllers
var contextUser = databaseContext.Users.Local.Where(x => x.Id == AuthenticationContext.User.Id).FirstOrDefault();
if (contextUser == default)
{
// No reason to call the DB, just attach it
contextUser = new Models.User
{
Id = AuthenticationContext.User.Id
+11 -8
View File
@@ -5,7 +5,6 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Cors.Infrastructure;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
@@ -67,9 +66,9 @@ namespace Tgstation.Server.Host.Core
readonly IIOManager ioManager;
/// <summary>
/// The <see cref="Microsoft.AspNetCore.Hosting.IHostingEnvironment"/> for the <see cref="Application"/>
/// The <see cref="IWebHostEnvironment"/> for the <see cref="Application"/>
/// </summary>
readonly Microsoft.AspNetCore.Hosting.IHostingEnvironment hostingEnvironment;
readonly IWebHostEnvironment hostingEnvironment;
/// <summary>
/// The <see cref="TaskCompletionSource{TResult}"/> used for determining when the <see cref="Application"/> is <see cref="Ready(Exception)"/>
@@ -91,7 +90,7 @@ namespace Tgstation.Server.Host.Core
public Application(
IConfiguration configuration,
IAssemblyInformationProvider assemblyInformationProvider,
Microsoft.AspNetCore.Hosting.IHostingEnvironment hostingEnvironment,
IWebHostEnvironment hostingEnvironment,
IIOManager ioManager)
{
this.configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
@@ -146,11 +145,13 @@ namespace Tgstation.Server.Host.Core
// temporarily build the service provider in it's current state
// do it here so we can run the setup wizard if necessary
// also allows us to get some options and other services we need for continued configuration
#pragma warning disable ASP0000 // Do not call 'IServiceCollection.BuildServiceProvider' in 'ConfigureServices'
using (var provider = services.BuildServiceProvider())
#pragma warning restore ASP0000 // Do not call 'IServiceCollection.BuildServiceProvider' in 'ConfigureServices'
{
// run the wizard if necessary
var setupWizard = provider.GetRequiredService<ISetupWizard>();
var applicationLifetime = provider.GetRequiredService<Microsoft.AspNetCore.Hosting.IApplicationLifetime>();
var applicationLifetime = provider.GetRequiredService<IHostApplicationLifetime>();
var setupWizardRan = setupWizard.CheckRunWizard(applicationLifetime.ApplicationStopping).GetAwaiter().GetResult();
// load the configuration options we need
@@ -242,9 +243,11 @@ namespace Tgstation.Server.Host.Core
// add mvc, configure the json serializer settings
services
.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddJsonOptions(options =>
.AddMvc(options =>
{
options.EnableEndpointRouting = false;
})
.AddNewtonsoftJson(options =>
{
options.AllowInputFormatterExceptionMessages = true;
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
@@ -36,9 +36,9 @@ namespace Tgstation.Server.Host.Core
readonly IConsole console;
/// <summary>
/// The <see cref="IHostingEnvironment"/> for the <see cref="SetupWizard"/>
/// The <see cref="IWebHostEnvironment"/> for the <see cref="SetupWizard"/>
/// </summary>
readonly IHostingEnvironment hostingEnvironment;
readonly IWebHostEnvironment hostingEnvironment;
/// <summary>
/// The <see cref="IApplication"/> for the <see cref="SetupWizard"/>
@@ -85,7 +85,7 @@ namespace Tgstation.Server.Host.Core
public SetupWizard(
IIOManager ioManager,
IConsole console,
IHostingEnvironment hostingEnvironment,
IWebHostEnvironment hostingEnvironment,
IApplication application,
IDatabaseConnectionFactory dbConnectionFactory,
IPlatformIdentifier platformIdentifier,
@@ -0,0 +1,60 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace Tgstation.Server.Host.Database
{
/// <inheritdoc />
sealed class DatabaseCollection<TModel> : IDatabaseCollection<TModel> where TModel : class
{
/// <summary>
/// The backing <see cref="DbSet{TEntity}"/>.
/// </summary>
readonly DbSet<TModel> dbSet;
/// <summary>
/// Initializes a new instance of the <see cref="DatabaseCollection{TModel}"/> <see langword="class"/>.
/// </summary>
/// <param name="dbSet">The value of <see cref="dbSet"/>.</param>
public DatabaseCollection(DbSet<TModel> dbSet)
{
this.dbSet = dbSet ?? throw new ArgumentNullException(nameof(dbSet));
}
/// <inheritdoc />
public IEnumerable<TModel> Local => dbSet.Local;
/// <inheritdoc />
public Type ElementType => dbSet.AsQueryable().ElementType;
/// <inheritdoc />
public Expression Expression => dbSet.AsQueryable().Expression;
/// <inheritdoc />
public IQueryProvider Provider => dbSet.AsQueryable().Provider;
/// <inheritdoc />
public void Add(TModel model) => dbSet.Add(model);
/// <inheritdoc />
public void AddRange(IEnumerable<TModel> models) => dbSet.AddRange(models);
/// <inheritdoc />
public void Attach(TModel model) => dbSet.Attach(model);
/// <inheritdoc />
public IEnumerator<TModel> GetEnumerator() => dbSet.AsQueryable().GetEnumerator();
/// <inheritdoc />
public void Remove(TModel model) => dbSet.Remove(model);
/// <inheritdoc />
public void RemoveRange(IEnumerable<TModel> models) => dbSet.RemoveRange(models);
/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator() => dbSet.AsQueryable().GetEnumerator();
}
}
@@ -19,43 +19,69 @@ namespace Tgstation.Server.Host.Database
#pragma warning disable CA1506 // TODO: Decomplexify
abstract class DatabaseContext<TParentContext> : DbContext, IDatabaseContext where TParentContext : DbContext
{
/// <inheritdoc />
/// <summary>
/// The <see cref="User"/>s in the <see cref="DatabaseContext{TParentContext}"/>.
/// </summary>
public DbSet<User> Users { get; set; }
/// <inheritdoc />
/// <summary>
/// The <see cref="Instance"/>s in the <see cref="DatabaseContext{TParentContext}"/>.
/// </summary>
public DbSet<Instance> Instances { get; set; }
/// <inheritdoc />
/// <summary>
/// The <see cref="CompileJob"/>s in the <see cref="DatabaseContext{TParentContext}"/>.
/// </summary>
public DbSet<CompileJob> CompileJobs { get; set; }
/// <inheritdoc />
/// <summary>
/// The <see cref="RevisionInformation"/>s in the <see cref="DatabaseContext{TParentContext}"/>.
/// </summary>
public DbSet<RevisionInformation> RevisionInformations { get; set; }
/// <inheritdoc />
/// <summary>
/// The <see cref="Models.DreamMakerSettings"/> in the <see cref="DatabaseContext{TParentContext}"/>.
/// </summary>
public DbSet<DreamMakerSettings> DreamMakerSettings { get; set; }
/// <inheritdoc />
/// <summary>
/// The <see cref="ChatBot"/>s in the <see cref="DatabaseContext{TParentContext}"/>.
/// </summary>
public DbSet<ChatBot> ChatBots { get; set; }
/// <inheritdoc />
/// <summary>
/// The <see cref="Models.DreamDaemonSettings"/> in the <see cref="DatabaseContext{TParentContext}"/>.
/// </summary>
public DbSet<DreamDaemonSettings> DreamDaemonSettings { get; set; }
/// <inheritdoc />
/// <summary>
/// The <see cref="Models.RepositorySettings"/> in the <see cref="DatabaseContext{TParentContext}"/>.
/// </summary>
public DbSet<RepositorySettings> RepositorySettings { get; set; }
/// <inheritdoc />
/// <summary>
/// The <see cref="InstanceUser"/>s in the <see cref="DatabaseContext{TParentContext}"/>.
/// </summary>
public DbSet<InstanceUser> InstanceUsers { get; set; }
/// <inheritdoc />
/// <summary>
/// The <see cref="ChatChannel"/>s in the <see cref="DatabaseContext{TParentContext}"/>.
/// </summary>
public DbSet<ChatChannel> ChatChannels { get; set; }
/// <inheritdoc />
/// <summary>
/// The <see cref="Job"/>s in the <see cref="DatabaseContext{TParentContext}"/>.
/// </summary>
public DbSet<Job> Jobs { get; set; }
/// <inheritdoc />
/// <summary>
/// The <see cref="ReattachInformation"/>s in the <see cref="DatabaseContext{TParentContext}"/>.
/// </summary>
public DbSet<ReattachInformation> ReattachInformations { get; set; }
/// <inheritdoc />
/// <summary>
/// The <see cref="WatchdogReattachInformation"/>s in the <see cref="DatabaseContext{TParentContext}"/>.
/// </summary>
public DbSet<WatchdogReattachInformation> WatchdogReattachInformations { get; set; }
/// <summary>
@@ -83,11 +109,115 @@ namespace Tgstation.Server.Host.Database
/// </summary>
protected abstract DatabaseType DatabaseType { get; }
/// <inheritdoc />
IDatabaseCollection<User> IDatabaseContext.Users => usersCollection;
/// <inheritdoc />
IDatabaseCollection<Instance> IDatabaseContext.Instances => instancesCollection;
/// <inheritdoc />
IDatabaseCollection<InstanceUser> IDatabaseContext.InstanceUsers => instanceUsersCollection;
/// <inheritdoc />
IDatabaseCollection<Job> IDatabaseContext.Jobs => jobsCollection;
/// <inheritdoc />
IDatabaseCollection<CompileJob> IDatabaseContext.CompileJobs => compileJobsCollection;
/// <inheritdoc />
IDatabaseCollection<RevisionInformation> IDatabaseContext.RevisionInformations => revisionInformationsCollection;
/// <inheritdoc />
IDatabaseCollection<DreamMakerSettings> IDatabaseContext.DreamMakerSettings => dreamMakerSettingsCollection;
/// <inheritdoc />
IDatabaseCollection<DreamDaemonSettings> IDatabaseContext.DreamDaemonSettings => dreamDaemonSettingsCollection;
/// <inheritdoc />
IDatabaseCollection<ChatBot> IDatabaseContext.ChatBots => chatBotsCollection;
/// <inheritdoc />
IDatabaseCollection<ChatChannel> IDatabaseContext.ChatChannels => chatChannelsCollection;
/// <inheritdoc />
IDatabaseCollection<RepositorySettings> IDatabaseContext.RepositorySettings => repositorySettingsCollection;
/// <inheritdoc />
IDatabaseCollection<ReattachInformation> IDatabaseContext.ReattachInformations => reattachInformationsCollection;
/// <inheritdoc />
IDatabaseCollection<WatchdogReattachInformation> IDatabaseContext.WatchdogReattachInformations => watchdogReattachInformationsCollection;
/// <summary>
/// The <see cref="IDatabaseSeeder"/> for the <see cref="DatabaseContext{TParentContext}"/>
/// </summary>
readonly IDatabaseSeeder databaseSeeder;
/// <summary>
/// Backing field for <see cref="IDatabaseContext.Users"/>.
/// </summary>
readonly IDatabaseCollection<User> usersCollection;
/// <summary>
/// Backing field for <see cref="IDatabaseContext.Instances"/>.
/// </summary>
readonly IDatabaseCollection<Instance> instancesCollection;
/// <summary>
/// Backing field for <see cref="IDatabaseContext.CompileJobs"/>.
/// </summary>
readonly IDatabaseCollection<CompileJob> compileJobsCollection;
/// <summary>
/// Backing field for <see cref="IDatabaseContext.InstanceUsers"/>.
/// </summary>
readonly IDatabaseCollection<InstanceUser> instanceUsersCollection;
/// <summary>
/// Backing field for <see cref="IDatabaseContext.Jobs"/>.
/// </summary>
readonly IDatabaseCollection<Job> jobsCollection;
/// <summary>
/// Backing field for <see cref="IDatabaseContext.RevisionInformations"/>.
/// </summary>
readonly IDatabaseCollection<RevisionInformation> revisionInformationsCollection;
/// <summary>
/// Backing field for <see cref="IDatabaseContext.DreamMakerSettings"/>.
/// </summary>
readonly IDatabaseCollection<DreamMakerSettings> dreamMakerSettingsCollection;
/// <summary>
/// Backing field for <see cref="IDatabaseContext.DreamDaemonSettings"/>.
/// </summary>
readonly IDatabaseCollection<DreamDaemonSettings> dreamDaemonSettingsCollection;
/// <summary>
/// Backing field for <see cref="IDatabaseContext.ChatBots"/>.
/// </summary>
readonly IDatabaseCollection<ChatBot> chatBotsCollection;
/// <summary>
/// Backing field for <see cref="IDatabaseContext.ChatChannels"/>.
/// </summary>
readonly IDatabaseCollection<ChatChannel> chatChannelsCollection;
/// <summary>
/// Backing field for <see cref="IDatabaseContext.RepositorySettings"/>.
/// </summary>
readonly IDatabaseCollection<RepositorySettings> repositorySettingsCollection;
/// <summary>
/// Backing field for <see cref="IDatabaseContext.ReattachInformations"/>.
/// </summary>
readonly IDatabaseCollection<ReattachInformation> reattachInformationsCollection;
/// <summary>
/// Backing field for <see cref="IDatabaseContext.WatchdogReattachInformations"/>.
/// </summary>
readonly IDatabaseCollection<WatchdogReattachInformation> watchdogReattachInformationsCollection;
/// <summary>
/// Construct a <see cref="DatabaseContext{TParentContext}"/>
/// </summary>
@@ -100,6 +230,20 @@ namespace Tgstation.Server.Host.Database
DatabaseConfiguration = databaseConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(databaseConfigurationOptions));
this.databaseSeeder = databaseSeeder ?? throw new ArgumentNullException(nameof(databaseSeeder));
Logger = logger ?? throw new ArgumentNullException(nameof(logger));
usersCollection = new DatabaseCollection<User>(Users);
instancesCollection = new DatabaseCollection<Instance>(Instances);
instanceUsersCollection = new DatabaseCollection<InstanceUser>(InstanceUsers);
compileJobsCollection = new DatabaseCollection<CompileJob>(CompileJobs);
repositorySettingsCollection = new DatabaseCollection<RepositorySettings>(RepositorySettings);
dreamMakerSettingsCollection = new DatabaseCollection<DreamMakerSettings>(DreamMakerSettings);
dreamDaemonSettingsCollection = new DatabaseCollection<DreamDaemonSettings>(DreamDaemonSettings);
chatBotsCollection = new DatabaseCollection<ChatBot>(ChatBots);
chatChannelsCollection = new DatabaseCollection<ChatChannel>(ChatChannels);
revisionInformationsCollection = new DatabaseCollection<RevisionInformation>(RevisionInformations);
jobsCollection = new DatabaseCollection<Job>(Jobs);
reattachInformationsCollection = new DatabaseCollection<ReattachInformation>(ReattachInformations);
watchdogReattachInformationsCollection = new DatabaseCollection<WatchdogReattachInformation>(WatchdogReattachInformations);
}
/// <inheritdoc />
@@ -166,7 +310,7 @@ namespace Tgstation.Server.Host.Database
else
Logger.LogDebug("No migrations to apply.");
wasEmpty |= (await Users.CountAsync(cancellationToken).ConfigureAwait(false)) == 0;
wasEmpty |= (await Users.AsQueryable().CountAsync(cancellationToken).ConfigureAwait(false)) == 0;
if (wasEmpty)
{
@@ -0,0 +1,47 @@
using System.Collections.Generic;
using System.Linq;
namespace Tgstation.Server.Host.Database
{
/// <summary>
/// Represents a database table.
/// </summary>
/// <typeparam name="TModel">The type of model.</typeparam>
public interface IDatabaseCollection<TModel> : IQueryable<TModel>
{
/// <summary>
/// An <see cref="IEnumerable{T}"/> of <typeparamref name="TModel"/>s prioritizing in the working set.
/// </summary>
IEnumerable<TModel> Local { get; }
/// <summary>
/// Add a given <paramref name="model"/> to the the working set.
/// </summary>
/// <param name="model">The <typeparamref name="TModel"/> model to add.</param>
void Add(TModel model);
/// <summary>
/// Remove a given <paramref name="model"/> from the the working set.
/// </summary>
/// <param name="model">The <typeparamref name="TModel"/> model to remove.</param>
void Remove(TModel model);
/// <summary>
/// Attach a given <paramref name="model"/> to the the working set.
/// </summary>
/// <param name="model">The <typeparamref name="TModel"/> model to add.</param>
void Attach(TModel model);
/// <summary>
/// Add a range of <paramref name="models"/> to the <see cref="IDatabaseCollection{TModel}"/>.
/// </summary>
/// <param name="models">An <see cref="IEnumerable{T}"/> of <typeparamref name="TModel"/>s to add.</param>
void AddRange(IEnumerable<TModel> models);
/// <summary>
/// Remove a range of <paramref name="models"/> from the <see cref="IDatabaseCollection{TModel}"/>.
/// </summary>
/// <param name="models">An <see cref="IEnumerable{T}"/> of <typeparamref name="TModel"/>s to remove.</param>
void RemoveRange(IEnumerable<TModel> models);
}
}
@@ -14,67 +14,67 @@ namespace Tgstation.Server.Host.Database
/// <summary>
/// The <see cref="User"/>s in the <see cref="IDatabaseContext"/>
/// </summary>
DbSet<User> Users { get; }
IDatabaseCollection<User> Users { get; }
/// <summary>
/// The <see cref="Instance"/>s in the <see cref="IDatabaseContext"/>
/// </summary>
DbSet<Instance> Instances { get; }
IDatabaseCollection<Instance> Instances { get; }
/// <summary>
/// The <see cref="InstanceUser"/>s in the <see cref="IDatabaseContext"/>
/// </summary>
DbSet<InstanceUser> InstanceUsers { get; }
IDatabaseCollection<InstanceUser> InstanceUsers { get; }
/// <summary>
/// The <see cref="Job"/>s in the <see cref="IDatabaseContext"/>
/// </summary>
DbSet<Job> Jobs { get; }
IDatabaseCollection<Job> Jobs { get; }
/// <summary>
/// The <see cref="CompileJob"/>s in the <see cref="IDatabaseContext"/>
/// </summary>
DbSet<CompileJob> CompileJobs { get; }
IDatabaseCollection<CompileJob> CompileJobs { get; }
/// <summary>
/// The <see cref="RevisionInformation"/>s in the <see cref="IDatabaseContext"/>
/// </summary>
DbSet<RevisionInformation> RevisionInformations { get; }
IDatabaseCollection<RevisionInformation> RevisionInformations { get; }
/// <summary>
/// The <see cref="Models.DreamMakerSettings"/> in the <see cref="IDatabaseContext"/>
/// </summary>
DbSet<DreamMakerSettings> DreamMakerSettings { get; set; }
IDatabaseCollection<DreamMakerSettings> DreamMakerSettings { get; }
/// <summary>
/// The <see cref="Models.DreamDaemonSettings"/> in the <see cref="IDatabaseContext"/>
/// </summary>
DbSet<DreamDaemonSettings> DreamDaemonSettings { get; set; }
IDatabaseCollection<DreamDaemonSettings> DreamDaemonSettings { get; }
/// <summary>
/// The <see cref="ChatBot"/>s in the <see cref="IDatabaseContext"/>
/// </summary>
DbSet<ChatBot> ChatBots { get; set; }
IDatabaseCollection<ChatBot> ChatBots { get; }
/// <summary>
/// The <see cref="ChatChannel"/> in the <see cref="IDatabaseContext"/>
/// </summary>
DbSet<ChatChannel> ChatChannels { get; set; }
IDatabaseCollection<ChatChannel> ChatChannels { get; }
/// <summary>
/// The <see cref="Models.RepositorySettings"/> in the <see cref="IDatabaseContext"/>
/// </summary>
DbSet<RepositorySettings> RepositorySettings { get; set; }
IDatabaseCollection<RepositorySettings> RepositorySettings { get; }
/// <summary>
/// The <see cref="DbSet{TEntity}"/> for <see cref="ReattachInformation"/>s
/// </summary>
DbSet<ReattachInformation> ReattachInformations { get; set; }
IDatabaseCollection<ReattachInformation> ReattachInformations { get; }
/// <summary>
/// The <see cref="DbSet{TEntity}"/> for <see cref="WatchdogReattachInformation"/>s
/// </summary>
DbSet<WatchdogReattachInformation> WatchdogReattachInformations { get; set; }
IDatabaseCollection<WatchdogReattachInformation> WatchdogReattachInformations { get; }
/// <summary>
/// Saves changes made to the <see cref="IDatabaseContext"/>
+12 -12
View File
@@ -1,5 +1,5 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
@@ -26,9 +26,9 @@ namespace Tgstation.Server.Host
public bool WatchdogPresent => updatePath != null;
/// <summary>
/// The <see cref="IWebHostBuilder"/> for the <see cref="Server"/>
/// The <see cref="IHostBuilder"/> for the <see cref="Server"/>
/// </summary>
readonly IWebHostBuilder webHostBuilder;
readonly IHostBuilder hostBuilder;
/// <summary>
/// The <see cref="IIOManager"/> for the <see cref="Server"/>.
@@ -73,16 +73,16 @@ namespace Tgstation.Server.Host
/// <summary>
/// Construct a <see cref="Server"/>
/// </summary>
/// <param name="webHostBuilder">The value of <see cref="webHostBuilder"/></param>
/// <param name="hostBuilder">The value of <see cref="hostBuilder"/></param>
/// <param name="ioManager">The value of <see cref="ioManager"/>.</param>
/// <param name="updatePath">The value of <see cref="updatePath"/></param>
public Server(IWebHostBuilder webHostBuilder, IIOManager ioManager, string updatePath)
public Server(IHostBuilder hostBuilder, IIOManager ioManager, string updatePath)
{
this.webHostBuilder = webHostBuilder ?? throw new ArgumentNullException(nameof(webHostBuilder));
this.hostBuilder = hostBuilder ?? throw new ArgumentNullException(nameof(hostBuilder));
this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
this.updatePath = updatePath;
webHostBuilder.ConfigureServices(serviceCollection => serviceCollection.AddSingleton<IServerControl>(this));
hostBuilder.ConfigureServices(serviceCollection => serviceCollection.AddSingleton<IServerControl>(this));
restartHandlers = new List<IRestartHandler>();
}
@@ -129,15 +129,15 @@ namespace Tgstation.Server.Host
fsWatcher.EnableRaisingEvents = true;
}
using (var webHost = webHostBuilder.Build())
using (var host = hostBuilder.Build())
try
{
logger = webHost.Services.GetRequiredService<ILogger<Server>>();
logger = host.Services.GetRequiredService<ILogger<Server>>();
using (cancellationToken.Register(() => logger.LogInformation("Process termination requested!")))
{
var generalConfigurationOptions = webHost.Services.GetRequiredService<IOptions<GeneralConfiguration>>();
var generalConfigurationOptions = host.Services.GetRequiredService<IOptions<GeneralConfiguration>>();
generalConfiguration = generalConfigurationOptions.Value;
await webHost.RunAsync(cancellationTokenSource.Token).ConfigureAwait(false);
await host.RunAsync(cancellationTokenSource.Token).ConfigureAwait(false);
}
}
catch (OperationCanceledException)
+13 -8
View File
@@ -1,7 +1,7 @@
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.IO;
using Tgstation.Server.Host.Core;
@@ -44,21 +44,26 @@ namespace Tgstation.Server.Host
/// <inheritdoc />
public IServer CreateServer(string[] args, string updatePath)
{
var webHost = WebHost.CreateDefaultBuilder(args ?? throw new ArgumentNullException(nameof(args)))
var hostBuilder = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(
args ?? throw new ArgumentNullException(nameof(args)))
.ConfigureAppConfiguration((context, configurationBuilder) => configurationBuilder.SetBasePath(Directory.GetCurrentDirectory()))
.ConfigureServices(serviceCollection =>
{
serviceCollection.AddSingleton(IOManager);
serviceCollection.AddSingleton(assemblyInformationProvider);
})
.UseStartup<Application>()
.SuppressStatusMessages(true)
.UseShutdownTimeout(TimeSpan.FromMinutes(1));
.ConfigureWebHostDefaults(webHostBuilder =>
{
webHostBuilder
.UseStartup<Application>()
.SuppressStatusMessages(true)
.UseShutdownTimeout(TimeSpan.FromMinutes(1));
});
if(updatePath != null)
webHost.UseContentRoot(Path.GetDirectoryName(assemblyInformationProvider.Path));
hostBuilder.UseContentRoot(Path.GetDirectoryName(assemblyInformationProvider.Path));
return new Server(webHost, IOManager, updatePath);
return new Server(hostBuilder, IOManager, updatePath);
}
}
}
@@ -2,22 +2,24 @@
<Import Project="../../build/Version.props" />
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
<DebugType>Full</DebugType>
<Version>$(TgsCoreVersion)</Version>
<LangVersion>latest</LangVersion>
<CodeAnalysisRuleSet>../../build/analyzers.ruleset</CodeAnalysisRuleSet>
<IsPackable>false</IsPackable>
<IncludeOpenAPIAnalyzers>true</IncludeOpenAPIAnalyzers>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsAsErrors />
<DocumentationFile>bin\Release\netcoreapp2.1\Tgstation.Server.Host.xml</DocumentationFile>
<NoWarn>API1000</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<NoWarn>1701;1702;SA1652;CA1063</NoWarn>
<NoWarn>API1000</NoWarn>
<DocumentationFile>bin\Debug\netcoreapp2.1\Tgstation.Server.Host.xml</DocumentationFile>
</PropertyGroup>
@@ -49,27 +51,27 @@
<PackageReference Include="Cyberboss.SmartIrc4net.Standard" Version="0.4.6" />
<PackageReference Include="Discord.Net.WebSocket" Version="2.2.0" />
<PackageReference Include="LibGit2Sharp" Version="0.27.0-preview-0034" />
<PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.3" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.3" />
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.2.6" PrivateAssets="All" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.2.6">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
<PackageReference Include="Octokit" Version="0.47.0" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.1.1" />
<!-- If this is updated, be sure to update the reference in the README.md -->
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.2.6" />
<PackageReference Include="Serilog.Extensions.Logging" Version="3.0.1" />
<PackageReference Include="Serilog.Sinks.Async" Version="1.4.0" />
<PackageReference Include="Serilog.Sinks.RollingFile" Version="3.3.0" />
@@ -79,11 +81,11 @@
</PackageReference>
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.3.2" />
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="5.3.2" />
<PackageReference Include="System.Diagnostics.PerformanceCounter" Version="4.7.0" />
<PackageReference Include="System.Data.SqlClient" Version="4.8.1" />
<PackageReference Include="System.DirectoryServices.AccountManagement" Version="4.7.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.5.0" />
<PackageReference Include="Wangkanai.Detection.Browser" Version="2.0.0" />
<PackageReference Include="Z.EntityFramework.Plus.EFCore" Version="2.0.32" />
<PackageReference Include="Z.EntityFramework.Plus.EFCore" Version="3.0.48" />
</ItemGroup>
<ItemGroup>
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net471</TargetFramework>
<TargetFramework>net472</TargetFramework>
<IsPackable>false</IsPackable>
<LangVersion>latest</LangVersion>
@@ -1,12 +1,11 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Host.Configuration;
@@ -34,7 +33,7 @@ namespace Tgstation.Server.Host.Core.Tests
Assert.ThrowsException<ArgumentNullException>(() => new Application(mockConfiguration.Object, mockAssemblyInfo.Object, null, null));
var mockHostingEnvironment = new Mock<IHostingEnvironment>();
var mockHostingEnvironment = new Mock<IWebHostEnvironment>();
Assert.ThrowsException<ArgumentNullException>(() => new Application(mockConfiguration.Object, mockAssemblyInfo.Object, mockHostingEnvironment.Object, null));
var app = new Application(mockConfiguration.Object, mockAssemblyInfo.Object, mockHostingEnvironment.Object, Mock.Of<IIOManager>());
@@ -67,7 +66,7 @@ namespace Tgstation.Server.Host.Core.Tests
public Task<bool> CheckRunWizard(CancellationToken cancellationToken) => Task.FromResult(true);
}
class MockApplicationLifetime : IApplicationLifetime
class MockHostApplicationLifetime : IHostApplicationLifetime
{
public CancellationToken ApplicationStarted => default;
@@ -77,42 +76,5 @@ namespace Tgstation.Server.Host.Core.Tests
public void StopApplication() { }
}
[TestMethod]
public void TestConfigureServicesThrowsWhenSetupWizardConfigurationDemands()
{
var mockConfiguration = new Mock<IConfiguration>();
var mockAssemblyInfo = new Mock<IAssemblyInformationProvider>();
mockAssemblyInfo.SetupGet(x => x.Name).Returns(typeof(Application).Assembly.GetName());
var mockHostingEnvironment = new Mock<IHostingEnvironment>();
var app = new Application(mockConfiguration.Object, mockAssemblyInfo.Object, mockHostingEnvironment.Object, Mock.Of<IIOManager>());
var mockOptions = new Mock<IOptions<GeneralConfiguration>>();
mockOptions.SetupGet(x => x.Value).Returns(new GeneralConfiguration
{
SetupWizardMode = SetupWizardMode.Only
}).Verifiable();
var fakeServiceDescriptor = new List<ServiceDescriptor>()
{
new ServiceDescriptor(typeof(IApplicationLifetime), typeof(MockApplicationLifetime), ServiceLifetime.Singleton),
new ServiceDescriptor(typeof(ISetupWizard), typeof(MockSetupWizard), ServiceLifetime.Singleton),
new ServiceDescriptor(typeof(IOptions<GeneralConfiguration>), mockOptions.Object)
};
var mockServiceCollection = new Mock<IServiceCollection>();
var mockConfigSection = new Mock<IConfigurationSection>();
mockConfiguration.Setup(x => x.GetSection(It.IsNotNull<string>())).Returns(mockConfigSection.Object).Verifiable();
mockServiceCollection.Setup(x => x.GetEnumerator()).Returns(() => fakeServiceDescriptor.GetEnumerator()).Verifiable();
Assert.ThrowsException<OperationCanceledException>(() => app.ConfigureServices(mockServiceCollection.Object));
mockOptions.VerifyAll();
mockConfiguration.VerifyAll();
mockServiceCollection.VerifyAll();
}
}
}
@@ -28,7 +28,7 @@ namespace Tgstation.Server.Host.Core.Tests
Assert.ThrowsException<ArgumentNullException>(() => new SetupWizard(mockIOManager.Object, null, null, null, null, null, null, null, null));
var mockConsole = new Mock<IConsole>();
Assert.ThrowsException<ArgumentNullException>(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, null, null, null, null, null, null, null));
var mockHostingEnvironment = new Mock<IHostingEnvironment>();
var mockHostingEnvironment = new Mock<IWebHostEnvironment>();
Assert.ThrowsException<ArgumentNullException>(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, null, null, null, null, null, null));
var mockApplication = new Mock<IApplication>();
Assert.ThrowsException<ArgumentNullException>(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockApplication.Object, null, null, null, null, null));
@@ -47,7 +47,7 @@ namespace Tgstation.Server.Host.Core.Tests
{
var mockIOManager = new Mock<IIOManager>();
var mockConsole = new Mock<IConsole>();
var mockHostingEnvironment = new Mock<IHostingEnvironment>();
var mockHostingEnvironment = new Mock<IWebHostEnvironment>();
var mockApplication = new Mock<IApplication>();
var mockDBConnectionFactory = new Mock<IDatabaseConnectionFactory>();
var mockLogger = new Mock<ILogger<SetupWizard>>();
@@ -76,7 +76,7 @@ namespace Tgstation.Server.Host.Core.Tests
mockConsole.SetupGet(x => x.Available).Returns(true).Verifiable();
mockIOManager.Setup(x => x.FileExists(It.IsNotNull<string>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult(true)).Verifiable();
mockIOManager.Setup(x => x.ReadAllBytes(It.IsNotNull<string>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult(Encoding.UTF8.GetBytes("cucked"))).Verifiable();
mockIOManager.Setup(x => x.ReadAllBytes(It.IsNotNull<string>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult(Encoding.UTF8.GetBytes("less profane"))).Verifiable();
mockIOManager.Setup(x => x.WriteAllBytes(It.IsNotNull<string>(), It.IsNotNull<byte[]>(), It.IsAny<CancellationToken>())).Returns(Task.CompletedTask).Verifiable();
var mockSuccessCommand = new Mock<DbCommand>();
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
<LangVersion>latest</LangVersion>
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
<LangVersion>latest</LangVersion>