tgstation-server 6.0.1
The /tg/station 13 server suite
Loading...
Searching...
No Matches
ApplicationBuilderExtensions.cs
Go to the documentation of this file.
1using System;
2using System.Globalization;
3using System.Net;
4
5using Microsoft.AspNetCore.Builder;
6using Microsoft.AspNetCore.Http;
7using Microsoft.AspNetCore.Mvc;
8using Microsoft.EntityFrameworkCore;
9using Microsoft.Extensions.DependencyInjection;
10using Microsoft.Extensions.Logging;
11
12using Serilog.Context;
13
19
21{
26 {
30 internal static bool LogSwarmIdentifier { get; set; }
31
36 public static void UseDbConflictHandling(this IApplicationBuilder applicationBuilder)
37 {
38 ArgumentNullException.ThrowIfNull(applicationBuilder);
39
40 applicationBuilder.Use(async (context, next) =>
41 {
42 var logger = GetLogger(context);
43 try
44 {
45 await next();
46 }
47 catch (DbUpdateException e)
48 {
49 if (e.InnerException is OperationCanceledException)
50 {
51 logger.LogTrace(e, "Rethrowing DbUpdateException as OperationCanceledException");
52 throw e.InnerException;
53 }
54
55 logger.LogDebug(e, "Database conflict!");
56 await new ConflictObjectResult(new ErrorMessageResponse(ErrorCode.DatabaseIntegrityConflict)
57 {
58 AdditionalData = String.Format(CultureInfo.InvariantCulture, (e.InnerException ?? e).Message),
59 }).ExecuteResultAsync(new ActionContext
60 {
61 HttpContext = context,
62 });
63 }
64 });
65 }
66
71 public static void UseCancelledRequestSuppression(this IApplicationBuilder applicationBuilder)
72 {
73 ArgumentNullException.ThrowIfNull(applicationBuilder);
74 applicationBuilder.Use(async (context, next) =>
75 {
76 var logger = GetLogger(context);
77 try
78 {
79 await next();
80 }
81 catch (OperationCanceledException ex)
82 {
83 logger.LogDebug(ex, "Request cancelled!");
84 }
85 });
86 }
87
92 public static void UseServerErrorHandling(this IApplicationBuilder applicationBuilder)
93 {
94 ArgumentNullException.ThrowIfNull(applicationBuilder);
95
96 applicationBuilder.Use(async (context, next) =>
97 {
98 var logger = GetLogger(context);
99 try
100 {
101 await next();
102 }
103 catch (Exception e)
104 {
105 logger.LogError(e, "Failed request!");
106 await new JsonResult(
107 new ErrorMessageResponse(ErrorCode.InternalServerError)
108 {
109 AdditionalData = e.ToString(),
110 })
111 {
112 StatusCode = (int)HttpStatusCode.InternalServerError,
113 }
114 .ExecuteResultAsync(new ActionContext
115 {
116 HttpContext = context,
117 });
118 }
119 });
120 }
121
126 public static void UseApiCompatibility(this IApplicationBuilder applicationBuilder)
127 {
128 ArgumentNullException.ThrowIfNull(applicationBuilder);
129
130 applicationBuilder.Use(async (context, next) =>
131 {
132 var apiHeadersProvider = context.RequestServices.GetRequiredService<IApiHeadersProvider>();
133 if (apiHeadersProvider.ApiHeaders?.Compatible() == false)
134 {
135 await new BadRequestObjectResult(
136 new ErrorMessageResponse(ErrorCode.ApiMismatch))
137 .ExecuteResultAsync(new ActionContext
138 {
139 HttpContext = context,
140 });
141 return;
142 }
143
144 await next();
145 });
146 }
147
153 public static void UseServerBranding(this IApplicationBuilder applicationBuilder, IAssemblyInformationProvider assemblyInformationProvider)
154 {
155 ArgumentNullException.ThrowIfNull(applicationBuilder);
156 ArgumentNullException.ThrowIfNull(assemblyInformationProvider);
157
158 applicationBuilder.Use((context, next) =>
159 {
160 context.Response.Headers.Add("X-Powered-By", assemblyInformationProvider.VersionPrefix);
161 return next();
162 });
163 }
164
170 public static void UseDisabledNginxProxyBuffering(this IApplicationBuilder applicationBuilder)
171 {
172 ArgumentNullException.ThrowIfNull(applicationBuilder);
173
174 // https://www.nginx.com/resources/wiki/start/topics/examples/x-accel/#x-accel-buffering
175 applicationBuilder.Use((context, next) =>
176 {
177 context.Response.Headers.Add("X-Accel-Buffering", "no");
178 return next();
179 });
180 }
181
187 public static void UseAdditionalRequestLoggingContext(this IApplicationBuilder applicationBuilder, SwarmConfiguration swarmConfiguration)
188 {
189 ArgumentNullException.ThrowIfNull(applicationBuilder);
190 ArgumentNullException.ThrowIfNull(swarmConfiguration);
191
192 if (LogSwarmIdentifier && swarmConfiguration.Identifier != null)
193 applicationBuilder.Use(async (context, next) =>
194 {
195 using (LogContext.PushProperty(SerilogContextHelper.SwarmIdentifierContextProperty, swarmConfiguration.Identifier))
196 await next();
197 });
198 }
199
205 static ILogger GetLogger(HttpContext httpContext) => httpContext.RequestServices.GetRequiredService<ILoggerFactory>().CreateLogger(typeof(ApplicationBuilderExtensions));
206 }
207}
string? Identifier
The server's identifier.
Definition: SwarmServer.cs:26
Represents an error message returned by the server.
Configuration for the server swarm system.
static void UseServerBranding(this IApplicationBuilder applicationBuilder, IAssemblyInformationProvider assemblyInformationProvider)
Add the X-Powered-By response header.
static void UseDisabledNginxProxyBuffering(this IApplicationBuilder applicationBuilder)
Add the X-Accel-Buffering response header.
static void UseServerErrorHandling(this IApplicationBuilder applicationBuilder)
Suppress all in flight Exceptions for the request with error 500.
static ILogger GetLogger(HttpContext httpContext)
Gets a ILogger from a given httpContext .
static void UseDbConflictHandling(this IApplicationBuilder applicationBuilder)
Return a ConflictObjectResult for DbUpdateExceptions.
static void UseCancelledRequestSuppression(this IApplicationBuilder applicationBuilder)
Suppress global::System.Threading.Tasks.TaskCanceledException warnings when a user aborts a request.
static void UseAdditionalRequestLoggingContext(this IApplicationBuilder applicationBuilder, SwarmConfiguration swarmConfiguration)
Adds additional global LogContext to the request pipeline.
static void UseApiCompatibility(this IApplicationBuilder applicationBuilder)
Check that the API version is the current major version if it's present in the headers.
Helpers for manipulating the Serilog.Context.LogContext.
const string SwarmIdentifierContextProperty
The Serilog.Context.LogContext property name for Api.Models.Internal.SwarmServer.Identifiers.
ErrorCode
Types of Response.ErrorMessageResponses that the API may return.
Definition: ErrorCode.cs:13