Handle database conflicts at a higher level with middleware

This commit is contained in:
Cyberboss
2018-08-15 14:32:47 -04:00
parent 7c223f428c
commit e8efcc1f60
8 changed files with 86 additions and 60 deletions
@@ -211,14 +211,7 @@ namespace Tgstation.Server.Host.Controllers
var attachFileName = ioManager.ConcatPath(originalModel.Path, InstanceAttachFileName);
await ioManager.WriteAllBytes(attachFileName, Array.Empty<byte>(), default).ConfigureAwait(false);
try
{
await DatabaseContext.Save(cancellationToken).ConfigureAwait(false); //cascades everything
}
catch (DbUpdateException e)
{
return Conflict(new ErrorMessage { Message = e.Message });
}
await DatabaseContext.Save(cancellationToken).ConfigureAwait(false); //cascades everything
return Ok();
}
@@ -69,14 +69,7 @@ namespace Tgstation.Server.Host.Controllers
DatabaseContext.InstanceUsers.Add(dbUser);
try
{
await DatabaseContext.Save(cancellationToken).ConfigureAwait(false);
}
catch (DbUpdateConcurrencyException e)
{
return Conflict(new ErrorMessage { Message = e.Message });
}
await DatabaseContext.Save(cancellationToken).ConfigureAwait(false);
return Json(dbUser.ToApi());
}
@@ -98,14 +91,7 @@ namespace Tgstation.Server.Host.Controllers
originalUser.DreamDaemonRights = model.DreamDaemonRights ?? originalUser.DreamDaemonRights;
originalUser.DreamMakerRights = model.DreamMakerRights ?? originalUser.DreamMakerRights;
try
{
await DatabaseContext.Save(cancellationToken).ConfigureAwait(false);
}
catch (DbUpdateConcurrencyException e)
{
return Conflict(new ErrorMessage { Message = e.Message });
}
await DatabaseContext.Save(cancellationToken).ConfigureAwait(false);
return Json(originalUser.ToApi());
}
@@ -116,22 +116,7 @@ namespace Tgstation.Server.Host.Controllers
DatabaseContext.Users.Add(dbUser);
try
{
try
{
await DatabaseContext.Save(cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
{
logger.LogInformation("Error creating user: {0}", e);
throw;
}
}
catch (DbUpdateConcurrencyException e)
{
return Conflict(new { message = e.Message });
}
await DatabaseContext.Save(cancellationToken).ConfigureAwait(false);
return Json(dbUser.ToApi());
}
@@ -22,7 +22,6 @@ using Tgstation.Server.Host.Components;
using Tgstation.Server.Host.Components.Byond;
using Tgstation.Server.Host.Components.Chat;
using Tgstation.Server.Host.Components.StaticFiles;
using Tgstation.Server.Host.Components.Watchdog;
using Tgstation.Server.Host.Configuration;
using Tgstation.Server.Host.Controllers;
using Tgstation.Server.Host.IO;
@@ -249,6 +248,9 @@ namespace Tgstation.Server.Host.Core
});
applicationBuilder.UseAuthentication();
applicationBuilder.UseDbConflictHandling();
applicationBuilder.UseMvc();
}
@@ -0,0 +1,36 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Globalization;
using Tgstation.Server.Api.Models;
namespace Tgstation.Server.Host.Core
{
/// <summary>
/// Extensions for <see cref="IApplicationBuilder"/>
/// </summary>
static class ApplicationBuilderExtensions
{
/// <summary>
/// Return a <see cref="ConflictObjectResult"/> for <see cref="DbUpdateException"/>s
/// </summary>
/// <param name="applicationBuilder">The <see cref="IApplicationBuilder"/> to configure</param>
public static void UseDbConflictHandling(this IApplicationBuilder applicationBuilder) => applicationBuilder.Use(async (context, next) =>
{
if (applicationBuilder == null)
throw new ArgumentNullException(nameof(applicationBuilder));
try
{
await next().ConfigureAwait(false);
}
catch (DbUpdateException e)
{
await new ConflictObjectResult(new ErrorMessage { Message = String.Format(CultureInfo.InvariantCulture, "A database conflict has occurred: {0}", (e.InnerException ?? e).Message) }).ExecuteResultAsync(new ActionContext
{
HttpContext = context
}).ConfigureAwait(false);
}
});
}
}
@@ -141,7 +141,7 @@ namespace Tgstation.Server.Host.Models
Logger.LogInformation("Migrating database...");
var wasEmpty = false;
if (!databaseConfiguration.NoMigrations)
if (databaseConfiguration.NoMigrations)
{
Logger.LogWarning("Using all or nothing migration strategy!");
await Database.EnsureCreatedAsync(cancellationToken).ConfigureAwait(false);
@@ -1,27 +1,12 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:52906/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Tgstation.Server.Host": {
"commandName": "Project",
"launchBrowser": true,
"launchBrowser": false,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:52907/"
"applicationUrl": "http://localhost:5000/"
}
}
}
+40 -1
View File
@@ -266,6 +266,45 @@
},
"response": []
},
{
"name": "Create User admin",
"request": {
"method": "PUT",
"header": [
{
"key": "Accept",
"value": "application/json"
},
{
"key": "User-Agent",
"value": "Postman/1.0"
},
{
"key": "Api",
"value": "Tgstation.Server.Api/4.0.0.0"
},
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"password\": \"asdfasdfasdfasdfasdf\",\n \"name\": \"admin\"\n}"
},
"url": {
"raw": "localhost:5000/User",
"host": [
"localhost"
],
"port": "5000",
"path": [
"User"
]
}
},
"response": []
},
{
"name": "Try To Add A SysId To User ID 2",
"request": {
@@ -544,7 +583,7 @@
],
"body": {
"mode": "raw",
"raw": "{\n \"systemIdentifier\": \"Cyberboss\"\n}"
"raw": "{\n \"systemIdentifier\": \"TESSONICS\\\\Jordan\"\n}"
},
"url": {
"raw": "localhost:5000/User",