update web project to .NET Core 3.1

This commit is contained in:
Jesse Plamondon-Willard 2020-05-07 22:41:37 -04:00
parent c58d01d0cf
commit a500812e88
No known key found for this signature in database
GPG Key ID: CF8B1456B3E29F49
8 changed files with 75 additions and 48 deletions

View File

@ -1,4 +1,5 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Tasks;
using Hangfire;
@ -36,7 +37,9 @@ namespace StardewModdingAPI.Web
/// <summary>Construct an instance.</summary>
/// <param name="wikiCache">The cache in which to store wiki metadata.</param>
/// <param name="modCache">The cache in which to store mod data.</param>
public BackgroundService(IWikiCacheRepository wikiCache, IModCacheRepository modCache)
/// <param name="hangfireStorage">The Hangfire storage implementation.</param>
[SuppressMessage("ReSharper", "UnusedParameter.Local", Justification = "The Hangfire reference forces it to initialize first, since it's needed by the background service.")]
public BackgroundService(IWikiCacheRepository wikiCache, IModCacheRepository modCache, JobStorage hangfireStorage)
{
BackgroundService.WikiCache = wikiCache;
BackgroundService.ModCache = modCache;

View File

@ -1,8 +1,12 @@
using System;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Routing;
using Newtonsoft.Json;
namespace StardewModdingAPI.Web.Framework
{
@ -34,5 +38,16 @@ namespace StardewModdingAPI.Web.Framework
}
return url;
}
/// <summary>Get a serialized JSON representation of the value.</summary>
/// <param name="page">The page to extend.</param>
/// <param name="value">The value to serialize.</param>
/// <returns>The serialized JSON.</returns>
/// <remarks>This bypasses unnecessary validation (e.g. not allowing null values) in <see cref="IJsonHelper.Serialize"/>.</remarks>
public static IHtmlContent ForJson(this RazorPageBase page, object value)
{
string json = JsonConvert.SerializeObject(value);
return new HtmlString(json);
}
}
}

View File

@ -1,5 +1,5 @@
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
namespace StardewModdingAPI.Web
{
@ -13,13 +13,13 @@ namespace StardewModdingAPI.Web
/// <param name="args">The command-line arguments.</param>
public static void Main(string[] args)
{
// configure web server
WebHost
Host
.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(builder => builder
.CaptureStartupErrors(true)
.UseSetting("detailedErrors", "true")
.UseKestrel().UseIISIntegration() // must be used together; fixes intermittent errors on Azure: https://stackoverflow.com/a/38312175/262123
.UseStartup<Startup>()
)
.Build()
.Run();
}

View File

@ -3,7 +3,7 @@
<PropertyGroup>
<AssemblyName>SMAPI.Web</AssemblyName>
<RootNamespace>StardewModdingAPI.Web</RootNamespace>
<TargetFramework>netcoreapp2.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
<LangVersion>latest</LangVersion>
</PropertyGroup>
@ -20,10 +20,7 @@
<PackageReference Include="Humanizer.Core" Version="2.8.11" />
<PackageReference Include="JetBrains.Annotations" Version="2020.1.0" />
<PackageReference Include="Markdig" Version="0.20.0" />
<PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Rewrite" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.0.2" />
<PackageReference Include="Mongo2Go" Version="2.2.12" />
<PackageReference Include="MongoDB.Driver" Version="2.10.4" />
<PackageReference Include="Newtonsoft.Json.Schema" Version="3.0.13" />

View File

@ -47,7 +47,7 @@ namespace StardewModdingAPI.Web
*********/
/// <summary>Construct an instance.</summary>
/// <param name="env">The hosting environment.</param>
public Startup(IHostingEnvironment env)
public Startup(IWebHostEnvironment env)
{
this.Configuration = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
@ -71,25 +71,16 @@ namespace StardewModdingAPI.Web
.Configure<SiteConfig>(this.Configuration.GetSection("Site"))
.Configure<RouteOptions>(options => options.ConstraintMap.Add("semanticVersion", typeof(VersionConstraint)))
.AddLogging()
.AddMemoryCache()
.AddMvc()
.ConfigureApplicationPartManager(manager => manager.FeatureProviders.Add(new InternalControllerFeatureProvider()))
.AddJsonOptions(options =>
{
foreach (JsonConverter converter in new JsonHelper().JsonSettings.Converters)
options.SerializerSettings.Converters.Add(converter);
options.SerializerSettings.Formatting = Formatting.Indented;
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
});
.AddMemoryCache();
MongoDbConfig mongoConfig = this.Configuration.GetSection("MongoDB").Get<MongoDbConfig>();
// init background service
{
BackgroundServicesConfig config = this.Configuration.GetSection("BackgroundServices").Get<BackgroundServicesConfig>();
if (config.Enabled)
services.AddHostedService<BackgroundService>();
}
// init MVC
services
.AddControllers()
.AddNewtonsoftJson(options => this.ConfigureJsonNet(options.SerializerSettings))
.ConfigureApplicationPartManager(manager => manager.FeatureProviders.Add(new InternalControllerFeatureProvider()));
services
.AddRazorPages();
// init MongoDB
services.AddSingleton<MongoDbRunner>(serv => !mongoConfig.IsConfigured()
@ -121,7 +112,7 @@ namespace StardewModdingAPI.Web
if (mongoConfig.IsConfigured())
{
config.UseMongoStorage(mongoConfig.ConnectionString, $"{mongoConfig.Database}-hangfire", new MongoStorageOptions
config.UseMongoStorage(MongoClientSettings.FromConnectionString(mongoConfig.ConnectionString), $"{mongoConfig.Database}-hangfire", new MongoStorageOptions
{
MigrationOptions = new MongoMigrationOptions(MongoMigrationStrategy.Drop),
CheckConnection = false // error on startup takes down entire process
@ -131,6 +122,13 @@ namespace StardewModdingAPI.Web
config.UseMemoryStorage();
});
// init background service
{
BackgroundServicesConfig config = this.Configuration.GetSection("BackgroundServices").Get<BackgroundServicesConfig>();
if (config.Enabled)
services.AddHostedService<BackgroundService>();
}
// init API clients
{
ApiClientsConfig api = this.Configuration.GetSection("ApiClients").Get<ApiClientsConfig>();
@ -188,8 +186,7 @@ namespace StardewModdingAPI.Web
/// <summary>The method called by the runtime to configure the HTTP request pipeline.</summary>
/// <param name="app">The application builder.</param>
/// <param name="env">The hosting environment.</param>
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
public void Configure(IApplicationBuilder app)
{
// basic config
app.UseDeveloperExceptionPage();
@ -201,7 +198,13 @@ namespace StardewModdingAPI.Web
)
.UseRewriter(this.GetRedirectRules())
.UseStaticFiles() // wwwroot folder
.UseMvc();
.UseRouting()
.UseAuthorization()
.UseEndpoints(p =>
{
p.MapControllers();
p.MapRazorPages();
});
// enable Hangfire dashboard
app.UseHangfireDashboard("/tasks", new DashboardOptions
@ -215,6 +218,17 @@ namespace StardewModdingAPI.Web
/*********
** Private methods
*********/
/// <summary>Configure a Json.NET serializer.</summary>
/// <param name="settings">The serializer settings to edit.</param>
private void ConfigureJsonNet(JsonSerializerSettings settings)
{
foreach (JsonConverter converter in new JsonHelper().JsonSettings.Converters)
settings.Converters.Add(converter);
settings.Formatting = Formatting.Indented;
settings.NullValueHandling = NullValueHandling.Ignore;
}
/// <summary>Get the redirect rules to apply.</summary>
private RewriteOptions GetRedirectRules()
{

View File

@ -40,7 +40,7 @@
<script src="~/Content/js/json-validator.js?r=202002"></script>
<script>
$(function() {
smapi.jsonValidator(@Json.Serialize(this.Url.PlainAction("Index", "JsonValidator", new { schemaName = "$schemaName", id = "$id" })), @Json.Serialize(Model.PasteID));
smapi.jsonValidator(@this.ForJson(this.Url.PlainAction("Index", "JsonValidator", new { schemaName = "$schemaName", id = "$id" })), @this.ForJson(Model.PasteID));
});
</script>
}

View File

@ -1,5 +1,4 @@
@using Humanizer
@using Newtonsoft.Json
@using StardewModdingAPI.Toolkit.Utilities
@using StardewModdingAPI.Web.Framework
@using StardewModdingAPI.Web.Framework.LogParsing.Models
@ -12,7 +11,6 @@
.GetValues(typeof(LogLevel))
.Cast<LogLevel>()
.ToDictionary(level => level.ToString().ToLower(), level => level != LogLevel.Trace);
JsonSerializerSettings noFormatting = new JsonSerializerSettings { Formatting = Formatting.None };
string curPageUrl = this.Url.PlainAction("Index", "LogParser", new { id = Model.PasteID }, absoluteUrl: true);
}
@ -32,12 +30,12 @@
<script>
$(function() {
smapi.logParser({
logStarted: new Date(@Json.Serialize(Model.ParsedLog?.Timestamp)),
showPopup: @Json.Serialize(Model.ParsedLog == null),
showMods: @Json.Serialize(Model.ParsedLog?.Mods?.Select(p => Model.GetSlug(p.Name)).Distinct().ToDictionary(slug => slug, slug => true), noFormatting),
showSections: @Json.Serialize(Enum.GetNames(typeof(LogSection)).ToDictionary(section => section, section => false), noFormatting),
showLevels: @Json.Serialize(defaultFilters, noFormatting),
enableFilters: @Json.Serialize(!Model.ShowRaw)
logStarted: new Date(@this.ForJson(Model.ParsedLog?.Timestamp)),
showPopup: @this.ForJson(Model.ParsedLog == null),
showMods: @this.ForJson(Model.ParsedLog?.Mods?.Select(p => Model.GetSlug(p.Name)).Distinct().ToDictionary(slug => slug, slug => true)),
showSections: @this.ForJson(Enum.GetNames(typeof(LogSection)).ToDictionary(section => section, section => false)),
showLevels: @this.ForJson(defaultFilters),
enableFilters: @this.ForJson(!Model.ShowRaw)
}, '@this.Url.PlainAction("Index", "LogParser", values: null)');
});
</script>

View File

@ -1,6 +1,6 @@
@using Humanizer
@using Humanizer.Localisation
@using Newtonsoft.Json
@using StardewModdingAPI.Web.Framework
@model StardewModdingAPI.Web.ViewModels.ModListModel
@{
ViewData["Title"] = "Mod compatibility";
@ -15,8 +15,8 @@
<script src="~/Content/js/mods.js?r=20200218"></script>
<script>
$(function() {
var data = @Json.Serialize(Model.Mods, new JsonSerializerSettings { Formatting = Formatting.None });
var enableBeta = @Json.Serialize(Model.BetaVersion != null);
var data = @this.ForJson(Model.Mods);
var enableBeta = @this.ForJson(Model.BetaVersion != null);
smapi.modList(data, enableBeta);
});
</script>
@ -86,7 +86,7 @@ else
</td>
<td class="mod-page-links">
<span v-for="(link, i) in mod.ModPages">
<a v-bind:href="link.Url">{{link.Text}}</a>{{i < mod.ModPages.length - 1 ? ', ' : ''}}
<a v-bind:href="link.Url">{{link.Text}}</a>{{i &lt; mod.ModPages.length - 1 ? ', ' : ''}}
</span>
</td>
<td>