fix memory leak issue related to AddDbContext not working as expected

This commit is contained in:
RaidMax 2020-11-29 16:01:52 -06:00
parent b2d282d412
commit bd3f0caf60
18 changed files with 499 additions and 505 deletions

View File

@ -48,10 +48,12 @@ namespace IW4MAdmin.Application.Extensions
return services; return services;
} }
public static IServiceCollection AddDatabaseContext(this IServiceCollection services, public static IServiceCollection AddDatabaseContextOptions(this IServiceCollection services,
ApplicationConfiguration appConfig) ApplicationConfiguration appConfig)
{ {
if (string.IsNullOrEmpty(appConfig.ConnectionString) || appConfig.DatabaseProvider == "sqlite") var activeProvider = appConfig.DatabaseProvider?.ToLower();
if (string.IsNullOrEmpty(appConfig.ConnectionString) || activeProvider == "sqlite")
{ {
var currentPath = Utilities.OperatingDirectory; var currentPath = Utilities.OperatingDirectory;
currentPath = !RuntimeInformation.IsOSPlatform(OSPlatform.Windows) currentPath = !RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
@ -62,31 +64,34 @@ namespace IW4MAdmin.Application.Extensions
{DataSource = Path.Join(currentPath, "Database", "Database.db")}; {DataSource = Path.Join(currentPath, "Database", "Database.db")};
var connectionString = connectionStringBuilder.ToString(); var connectionString = connectionStringBuilder.ToString();
services.AddDbContext<DatabaseContext, SqliteDatabaseContext>(options => var builder = new DbContextOptionsBuilder<SqliteDatabaseContext>()
options.UseSqlite(connectionString), ServiceLifetime.Transient); .UseSqlite(connectionString);
services.AddSingleton((DbContextOptions) builder.Options);
return services; return services;
} }
switch (appConfig.DatabaseProvider) switch (activeProvider)
{ {
case "mysql": case "mysql":
var appendTimeout = !appConfig.ConnectionString.Contains("default command timeout", var appendTimeout = !appConfig.ConnectionString.Contains("default command timeout",
StringComparison.InvariantCultureIgnoreCase); StringComparison.InvariantCultureIgnoreCase);
services.AddDbContext<DatabaseContext, MySqlDatabaseContext>(options => var mysqlBuilder = new DbContextOptionsBuilder<MySqlDatabaseContext>()
options.UseMySql( .UseMySql(appConfig.ConnectionString + (appendTimeout ? ";default command timeout=0" : ""),
appConfig.ConnectionString + (appendTimeout ? ";default command timeout=0" : ""), mysqlOptions => mysqlOptions.EnableRetryOnFailure());
mysqlOptions => mysqlOptions.EnableRetryOnFailure()), ServiceLifetime.Transient); services.AddSingleton((DbContextOptions) mysqlBuilder.Options);
break; return services;
case "postgresql": case "postgresql":
appendTimeout = !appConfig.ConnectionString.Contains("Command Timeout", appendTimeout = !appConfig.ConnectionString.Contains("Command Timeout",
StringComparison.InvariantCultureIgnoreCase); StringComparison.InvariantCultureIgnoreCase);
services.AddDbContext<DatabaseContext, PostgresqlDatabaseContext>(options => var postgresqlBuilder = new DbContextOptionsBuilder<PostgresqlDatabaseContext>()
options.UseNpgsql(appConfig.ConnectionString + (appendTimeout ? ";Command Timeout=0" : ""), .UseNpgsql(appConfig.ConnectionString + (appendTimeout ? ";Command Timeout=0" : ""),
postgresqlOptions => postgresqlOptions.EnableRetryOnFailure()), ServiceLifetime.Transient); postgresqlOptions => postgresqlOptions.EnableRetryOnFailure());
break; services.AddSingleton((DbContextOptions) postgresqlBuilder.Options);
}
return services; return services;
default:
throw new ArgumentException($"No context available for {appConfig.DatabaseProvider}");
}
} }
} }
} }

View File

@ -1,7 +1,8 @@
using System; using System;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection; using SharedLibraryCore.Configuration;
using SharedLibraryCore.Database; using SharedLibraryCore.Database;
using SharedLibraryCore.Database.MigrationContext;
using SharedLibraryCore.Interfaces; using SharedLibraryCore.Interfaces;
namespace IW4MAdmin.Application.Factories namespace IW4MAdmin.Application.Factories
@ -11,11 +12,13 @@ namespace IW4MAdmin.Application.Factories
/// </summary> /// </summary>
public class DatabaseContextFactory : IDatabaseContextFactory public class DatabaseContextFactory : IDatabaseContextFactory
{ {
private readonly IServiceProvider _serviceProvider; private readonly DbContextOptions _contextOptions;
private readonly string _activeProvider;
public DatabaseContextFactory(IServiceProvider serviceProvider) public DatabaseContextFactory(ApplicationConfiguration appConfig, DbContextOptions contextOptions)
{ {
_serviceProvider = serviceProvider; _contextOptions = contextOptions;
_activeProvider = appConfig.DatabaseProvider?.ToLower();
} }
/// <summary> /// <summary>
@ -25,7 +28,7 @@ namespace IW4MAdmin.Application.Factories
/// <returns></returns> /// <returns></returns>
public DatabaseContext CreateContext(bool? enableTracking = true) public DatabaseContext CreateContext(bool? enableTracking = true)
{ {
var context = _serviceProvider.GetRequiredService<DatabaseContext>(); var context = BuildContext();
enableTracking ??= true; enableTracking ??= true;
@ -44,5 +47,16 @@ namespace IW4MAdmin.Application.Factories
return context; return context;
} }
private DatabaseContext BuildContext()
{
return _activeProvider switch
{
"sqlite" => new SqliteDatabaseContext(_contextOptions),
"mysql" => new MySqlDatabaseContext(_contextOptions),
"postgresql" => new PostgresqlDatabaseContext(_contextOptions),
_ => throw new ArgumentException($"No context found for {_activeProvider}")
};
}
} }
} }

View File

@ -361,7 +361,7 @@ namespace IW4MAdmin.Application
.AddSingleton<SharedLibraryCore.Interfaces.ILogger, Logger>() .AddSingleton<SharedLibraryCore.Interfaces.ILogger, Logger>()
.AddSingleton<IClientNoticeMessageFormatter, ClientNoticeMessageFormatter>() .AddSingleton<IClientNoticeMessageFormatter, ClientNoticeMessageFormatter>()
.AddSingleton(translationLookup) .AddSingleton(translationLookup)
.AddDatabaseContext(appConfig); .AddDatabaseContextOptions(appConfig);
if (args.Contains("serialevents")) if (args.Contains("serialevents"))
{ {

View File

@ -28,7 +28,7 @@ namespace IW4MAdmin.Application.Meta
public async Task<ResourceQueryHelperResult<AdministeredPenaltyResponse>> QueryResource(ClientPaginationRequest query) public async Task<ResourceQueryHelperResult<AdministeredPenaltyResponse>> QueryResource(ClientPaginationRequest query)
{ {
using var ctx = _contextFactory.CreateContext(enableTracking: false); await using var ctx = _contextFactory.CreateContext(enableTracking: false);
var iqPenalties = ctx.Penalties.AsNoTracking() var iqPenalties = ctx.Penalties.AsNoTracking()
.Where(_penalty => query.ClientId == _penalty.PunisherId) .Where(_penalty => query.ClientId == _penalty.PunisherId)

View File

@ -31,7 +31,7 @@ namespace IW4MAdmin.Application.Meta
public async Task<ResourceQueryHelperResult<ReceivedPenaltyResponse>> QueryResource(ClientPaginationRequest query) public async Task<ResourceQueryHelperResult<ReceivedPenaltyResponse>> QueryResource(ClientPaginationRequest query)
{ {
var linkedPenaltyType = Utilities.LinkedPenaltyTypes(); var linkedPenaltyType = Utilities.LinkedPenaltyTypes();
using var ctx = _contextFactory.CreateContext(enableTracking: false); await using var ctx = _contextFactory.CreateContext(enableTracking: false);
var linkId = await ctx.Clients.AsNoTracking() var linkId = await ctx.Clients.AsNoTracking()
.Where(_client => _client.ClientId == query.ClientId) .Where(_client => _client.ClientId == query.ClientId)

View File

@ -28,7 +28,7 @@ namespace IW4MAdmin.Application.Meta
public async Task<ResourceQueryHelperResult<UpdatedAliasResponse>> QueryResource(ClientPaginationRequest query) public async Task<ResourceQueryHelperResult<UpdatedAliasResponse>> QueryResource(ClientPaginationRequest query)
{ {
using var ctx = _contextFactory.CreateContext(enableTracking: false); await using var ctx = _contextFactory.CreateContext(enableTracking: false);
int linkId = ctx.Clients.First(_client => _client.ClientId == query.ClientId).AliasLinkId; int linkId = ctx.Clients.First(_client => _client.ClientId == query.ClientId).AliasLinkId;
var iqAliasUpdates = ctx.Aliases var iqAliasUpdates = ctx.Aliases

View File

@ -37,7 +37,7 @@ namespace IW4MAdmin.Application.Misc
return; return;
} }
using var ctx = _contextFactory.CreateContext(); await using var ctx = _contextFactory.CreateContext();
var existingMeta = await ctx.EFMeta var existingMeta = await ctx.EFMeta
.Where(_meta => _meta.Key == metaKey) .Where(_meta => _meta.Key == metaKey)
@ -66,7 +66,7 @@ namespace IW4MAdmin.Application.Misc
public async Task<EFMeta> GetPersistentMeta(string metaKey, EFClient client) public async Task<EFMeta> GetPersistentMeta(string metaKey, EFClient client)
{ {
using var ctx = _contextFactory.CreateContext(enableTracking: false); await using var ctx = _contextFactory.CreateContext(enableTracking: false);
return await ctx.EFMeta return await ctx.EFMeta
.Where(_meta => _meta.Key == metaKey) .Where(_meta => _meta.Key == metaKey)

View File

@ -2,7 +2,6 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using SharedLibraryCore; using SharedLibraryCore;
using IW4MAdmin.Plugins.Stats.Models; using IW4MAdmin.Plugins.Stats.Models;
using System.Collections.Generic; using System.Collections.Generic;
@ -19,7 +18,8 @@ namespace IW4MAdmin.Plugins.Stats.Commands
private readonly IDatabaseContextFactory _contextFactory; private readonly IDatabaseContextFactory _contextFactory;
private readonly CommandConfiguration _config; private readonly CommandConfiguration _config;
public MostKillsCommand(CommandConfiguration config, ITranslationLookup translationLookup, IDatabaseContextFactory contextFactory) : base(config, translationLookup) public MostKillsCommand(CommandConfiguration config, ITranslationLookup translationLookup,
IDatabaseContextFactory contextFactory) : base(config, translationLookup)
{ {
Name = "mostkills"; Name = "mostkills";
Description = translationLookup["PLUGINS_STATS_COMMANDS_MOSTKILLS_DESC"]; Description = translationLookup["PLUGINS_STATS_COMMANDS_MOSTKILLS_DESC"];
@ -32,7 +32,8 @@ namespace IW4MAdmin.Plugins.Stats.Commands
public override async Task ExecuteAsync(GameEvent E) public override async Task ExecuteAsync(GameEvent E)
{ {
var mostKills = await GetMostKills(StatManager.GetIdForServer(E.Owner), Plugin.Config.Configuration(), _contextFactory, _translationLookup); var mostKills = await GetMostKills(StatManager.GetIdForServer(E.Owner), Plugin.Config.Configuration(),
_contextFactory, _translationLookup);
if (!E.Message.IsBroadcastCommand(_config.BroadcastCommandPrefix)) if (!E.Message.IsBroadcastCommand(_config.BroadcastCommandPrefix))
{ {
foreach (var stat in mostKills) foreach (var stat in mostKills)
@ -50,10 +51,10 @@ namespace IW4MAdmin.Plugins.Stats.Commands
} }
} }
public static async Task<IEnumerable<string>> GetMostKills(long? serverId, StatsConfiguration config, IDatabaseContextFactory contextFactory, ITranslationLookup translationLookup) public static async Task<IEnumerable<string>> GetMostKills(long? serverId, StatsConfiguration config,
{ IDatabaseContextFactory contextFactory, ITranslationLookup translationLookup)
using (var ctx = contextFactory.CreateContext(enableTracking: false))
{ {
await using var ctx = contextFactory.CreateContext(enableTracking: false);
var dayInPast = DateTime.UtcNow.AddDays(-config.MostKillsMaxInactivityDays); var dayInPast = DateTime.UtcNow.AddDays(-config.MostKillsMaxInactivityDays);
var iqStats = (from stats in ctx.Set<EFClientStatistics>() var iqStats = (from stats in ctx.Set<EFClientStatistics>()
@ -74,9 +75,9 @@ namespace IW4MAdmin.Plugins.Stats.Commands
var iqList = await iqStats.ToListAsync(); var iqList = await iqStats.ToListAsync();
return iqList.Select((stats, index) => translationLookup["PLUGINS_STATS_COMMANDS_MOSTKILLS_FORMAT"].FormatExt(index + 1, stats.Name, stats.Kills)) return iqList.Select((stats, index) => translationLookup["PLUGINS_STATS_COMMANDS_MOSTKILLS_FORMAT"]
.FormatExt(index + 1, stats.Name, stats.Kills))
.Prepend(Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_COMMANDS_MOSTKILLS_HEADER"]); .Prepend(Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_COMMANDS_MOSTKILLS_HEADER"]);
} }
} }
} }
}

View File

@ -68,8 +68,8 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
/// <returns></returns> /// <returns></returns>
public async Task<int> GetClientOverallRanking(int clientId) public async Task<int> GetClientOverallRanking(int clientId)
{ {
using (var context = _contextFactory.CreateContext(enableTracking: false)) await using var context = _contextFactory.CreateContext(enableTracking: false);
{
var clientPerformance = await context.Set<EFRating>() var clientPerformance = await context.Set<EFRating>()
.Where(r => r.RatingHistory.ClientId == clientId) .Where(r => r.RatingHistory.ClientId == clientId)
.Where(r => r.ServerId == null) .Where(r => r.ServerId == null)
@ -89,12 +89,10 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
return 0; return 0;
} }
}
public async Task<List<TopStatsInfo>> GetTopStats(int start, int count, long? serverId = null) public async Task<List<TopStatsInfo>> GetTopStats(int start, int count, long? serverId = null)
{ {
using (var context = _contextFactory.CreateContext(enableTracking: false)) await using var context = _contextFactory.CreateContext(enableTracking: false);
{
// setup the query for the clients within the given rating range // setup the query for the clients within the given rating range
var iqClientRatings = (from rating in context.Set<EFRating>() var iqClientRatings = (from rating in context.Set<EFRating>()
.Where(GetRankingFunc(serverId)) .Where(GetRankingFunc(serverId))
@ -183,7 +181,6 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
return finished; return finished;
} }
}
/// <summary> /// <summary>
/// Add a server to the StatManager server pool /// Add a server to the StatManager server pool
@ -202,8 +199,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
long serverId = GetIdForServer(sv); long serverId = GetIdForServer(sv);
EFServer server; EFServer server;
using (var ctx = _contextFactory.CreateContext(enableTracking: false)) using var ctx = _contextFactory.CreateContext(enableTracking: false);
{
var serverSet = ctx.Set<EFServer>(); var serverSet = ctx.Set<EFServer>();
// get the server from the database if it exists, otherwise create and insert a new one // get the server from the database if it exists, otherwise create and insert a new one
server = serverSet.FirstOrDefault(s => s.ServerId == serverId); server = serverSet.FirstOrDefault(s => s.ServerId == serverId);
@ -257,7 +253,6 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
ctx.Entry(server).Property(_prop => _prop.IsPasswordProtected).IsModified = true; ctx.Entry(server).Property(_prop => _prop.IsPasswordProtected).IsModified = true;
server.IsPasswordProtected = !string.IsNullOrEmpty(sv.GamePassword); server.IsPasswordProtected = !string.IsNullOrEmpty(sv.GamePassword);
ctx.SaveChanges(); ctx.SaveChanges();
}
// check to see if the stats have ever been initialized // check to see if the stats have ever been initialized
var serverStats = InitializeServerStats(server.ServerId); var serverStats = InitializeServerStats(server.ServerId);
@ -304,8 +299,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
EFClientStatistics clientStats; EFClientStatistics clientStats;
using (var ctx = _contextFactory.CreateContext(enableTracking: false)) await using var ctx = _contextFactory.CreateContext(enableTracking: false);
{
var clientStatsSet = ctx.Set<EFClientStatistics>(); var clientStatsSet = ctx.Set<EFClientStatistics>();
clientStats = clientStatsSet clientStats = clientStatsSet
.Include(cl => cl.HitLocations) .Include(cl => cl.HitLocations)
@ -375,7 +369,6 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
pl.SetAdditionalProperty(CLIENT_DETECTIONS_KEY, new Detection(_log, clientStats)); pl.SetAdditionalProperty(CLIENT_DETECTIONS_KEY, new Detection(_log, clientStats));
_log.LogDebug("Added {client} to stats", pl.ToString()); _log.LogDebug("Added {client} to stats", pl.ToString());
}
return clientStats; return clientStats;
} }
@ -434,12 +427,10 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
private async Task SaveClientStats(EFClientStatistics clientStats) private async Task SaveClientStats(EFClientStatistics clientStats)
{ {
using (var ctx = _contextFactory.CreateContext()) await using var ctx = _contextFactory.CreateContext();
{
ctx.Update(clientStats); ctx.Update(clientStats);
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
} }
}
public void AddDamageEvent(string eventLine, int attackerClientId, int victimClientId, long serverId) public void AddDamageEvent(string eventLine, int attackerClientId, int victimClientId, long serverId)
{ {
@ -628,14 +619,12 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
public async Task SaveHitCache(long serverId) public async Task SaveHitCache(long serverId)
{ {
using (var ctx = _contextFactory.CreateContext(enableTracking: false)) await using var ctx = _contextFactory.CreateContext(enableTracking: false);
{
var server = _servers[serverId]; var server = _servers[serverId];
ctx.AddRange(server.HitCache.ToList()); ctx.AddRange(server.HitCache.ToList());
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
server.HitCache.Clear(); server.HitCache.Clear();
} }
}
private bool ShouldUseDetection(Server server, DetectionType detectionType, long clientId) private bool ShouldUseDetection(Server server, DetectionType detectionType, long clientId)
{ {
@ -714,15 +703,13 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
{ {
EFACSnapshot change; EFACSnapshot change;
using (var ctx = _contextFactory.CreateContext(enableTracking: false)) await using var ctx = _contextFactory.CreateContext();
{
while ((change = clientDetection.Tracker.GetNextChange()) != default(EFACSnapshot)) while ((change = clientDetection.Tracker.GetNextChange()) != default(EFACSnapshot))
{ {
ctx.Add(change); ctx.Add(change);
} }
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
} }
}
public async Task AddStandardKill(EFClient attacker, EFClient victim) public async Task AddStandardKill(EFClient attacker, EFClient victim)
{ {
@ -826,8 +813,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
int currentServerTotalPlaytime = clientStats.TimePlayed + currentSessionTime; int currentServerTotalPlaytime = clientStats.TimePlayed + currentSessionTime;
using (var ctx = _contextFactory.CreateContext(enableTracking: true)) await using var ctx = _contextFactory.CreateContext(enableTracking: true);
{
// select the rating history for client // select the rating history for client
var iqHistoryLink = from history in ctx.Set<EFClientRatingHistory>() var iqHistoryLink = from history in ctx.Set<EFClientRatingHistory>()
.Include(h => h.Ratings) .Include(h => h.Ratings)
@ -980,7 +966,6 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
} }
}
/// <summary> /// <summary>
/// Performs the incrementation of kills and deaths for client statistics /// Performs the incrementation of kills and deaths for client statistics
@ -1137,8 +1122,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
{ {
EFServerStatistics serverStats; EFServerStatistics serverStats;
using (var ctx = _contextFactory.CreateContext(enableTracking: false)) using var ctx = _contextFactory.CreateContext(enableTracking: false);
{
var serverStatsSet = ctx.Set<EFServerStatistics>(); var serverStatsSet = ctx.Set<EFServerStatistics>();
serverStats = serverStatsSet.FirstOrDefault(s => s.ServerId == serverId); serverStats = serverStatsSet.FirstOrDefault(s => s.ServerId == serverId);
@ -1156,7 +1140,6 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
serverStats = serverStatsSet.Add(serverStats).Entity; serverStats = serverStatsSet.Add(serverStats).Entity;
ctx.SaveChanges(); ctx.SaveChanges();
} }
}
return serverStats; return serverStats;
} }
@ -1216,12 +1199,10 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
{ {
await waiter.WaitAsync(); await waiter.WaitAsync();
using (var ctx = _contextFactory.CreateContext()) await using var ctx = _contextFactory.CreateContext();
{
var serverStatsSet = ctx.Set<EFServerStatistics>(); var serverStatsSet = ctx.Set<EFServerStatistics>();
serverStatsSet.Update(_servers[serverId].ServerStatistics); serverStatsSet.Update(_servers[serverId].ServerStatistics);
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
}
foreach (var stats in sv.GetClientsAsList() foreach (var stats in sv.GetClientsAsList()
.Select(_client => _client.GetAdditionalProperty<EFClientStatistics>(CLIENT_STATS_KEY)) .Select(_client => _client.GetAdditionalProperty<EFClientStatistics>(CLIENT_STATS_KEY))

View File

@ -26,7 +26,7 @@ namespace Stats.Helpers
public async Task<ResourceQueryHelperResult<StatsInfoResult>> QueryResource(StatsInfoRequest query) public async Task<ResourceQueryHelperResult<StatsInfoResult>> QueryResource(StatsInfoRequest query)
{ {
var result = new ResourceQueryHelperResult<StatsInfoResult>(); var result = new ResourceQueryHelperResult<StatsInfoResult>();
using var context = _contextFactory.CreateContext(enableTracking: false); await using var context = _contextFactory.CreateContext(enableTracking: false);
// we need to get the ratings separately because there's not explicit FK // we need to get the ratings separately because there's not explicit FK
var ratings = await context.Set<EFClientRatingHistory>() var ratings = await context.Set<EFClientRatingHistory>()

View File

@ -173,11 +173,9 @@ namespace IW4MAdmin.Plugins.Stats
{ {
IList<EFClientStatistics> clientStats; IList<EFClientStatistics> clientStats;
int messageCount = 0; int messageCount = 0;
using (var ctx = _databaseContextFactory.CreateContext(enableTracking: false)) await using var ctx = _databaseContextFactory.CreateContext(enableTracking: false);
{
clientStats = await ctx.Set<EFClientStatistics>().Where(c => c.ClientId == request.ClientId).ToListAsync(); clientStats = await ctx.Set<EFClientStatistics>().Where(c => c.ClientId == request.ClientId).ToListAsync();
messageCount = await ctx.Set<EFClientMessage>().CountAsync(_message => _message.ClientId == request.ClientId); messageCount = await ctx.Set<EFClientMessage>().CountAsync(_message => _message.ClientId == request.ClientId);
}
int kills = clientStats.Sum(c => c.Kills); int kills = clientStats.Sum(c => c.Kills);
int deaths = clientStats.Sum(c => c.Deaths); int deaths = clientStats.Sum(c => c.Deaths);
@ -252,13 +250,11 @@ namespace IW4MAdmin.Plugins.Stats
{ {
IList<EFClientStatistics> clientStats; IList<EFClientStatistics> clientStats;
using (var ctx = _databaseContextFactory.CreateContext(enableTracking: false)) await using var ctx = _databaseContextFactory.CreateContext(enableTracking: false);
{
clientStats = await ctx.Set<EFClientStatistics>() clientStats = await ctx.Set<EFClientStatistics>()
.Include(c => c.HitLocations) .Include(c => c.HitLocations)
.Where(c => c.ClientId == request.ClientId) .Where(c => c.ClientId == request.ClientId)
.ToListAsync(); .ToListAsync();
}
double headRatio = 0; double headRatio = 0;
double chestRatio = 0; double chestRatio = 0;

View File

@ -41,7 +41,7 @@ namespace StatsWeb
} }
var result = new ResourceQueryHelperResult<MessageResponse>(); var result = new ResourceQueryHelperResult<MessageResponse>();
using var context = _contextFactory.CreateContext(enableTracking: false); await using var context = _contextFactory.CreateContext(enableTracking: false);
if (serverCache == null) if (serverCache == null)
{ {

View File

@ -13,7 +13,7 @@ namespace SharedLibraryCore.Database
{ {
public static async Task Seed(IDatabaseContextFactory contextFactory, CancellationToken token) public static async Task Seed(IDatabaseContextFactory contextFactory, CancellationToken token)
{ {
var context = contextFactory.CreateContext(); await using var context = contextFactory.CreateContext();
var strategy = context.Database.CreateExecutionStrategy(); var strategy = context.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () => await strategy.ExecuteAsync(async () =>
{ {

View File

@ -13,7 +13,7 @@ namespace SharedLibraryCore.Database.MigrationContext
} }
} }
public MySqlDatabaseContext(DbContextOptions<MySqlDatabaseContext> options) : base(options) public MySqlDatabaseContext(DbContextOptions options) : base(options)
{ {
} }

View File

@ -13,7 +13,7 @@ namespace SharedLibraryCore.Database.MigrationContext
} }
} }
public PostgresqlDatabaseContext(DbContextOptions<PostgresqlDatabaseContext> options) : base(options) public PostgresqlDatabaseContext(DbContextOptions options) : base(options)
{ {
} }

View File

@ -13,7 +13,7 @@ namespace SharedLibraryCore.Database.MigrationContext
} }
} }
public SqliteDatabaseContext(DbContextOptions<SqliteDatabaseContext> options) : base(options) public SqliteDatabaseContext(DbContextOptions options) : base(options)
{ {
} }

View File

@ -91,12 +91,11 @@ namespace SharedLibraryCore.Database.Models
SetAdditionalProperty("_reportCount", 0); SetAdditionalProperty("_reportCount", 0);
ReceivedPenalties = new List<EFPenalty>(); ReceivedPenalties = new List<EFPenalty>();
_processingEvent = new SemaphoreSlim(1, 1); _processingEvent = new SemaphoreSlim(1, 1);
} }
~EFClient() ~EFClient()
{ {
_processingEvent.Dispose(); _processingEvent?.Dispose();
} }
public override string ToString() public override string ToString()

View File

@ -22,8 +22,7 @@ namespace SharedLibraryCore.Repositories
/// <inheritdoc/> /// <inheritdoc/>
public async Task<IList<AuditInfo>> ListAuditInformation(PaginationRequest paginationInfo) public async Task<IList<AuditInfo>> ListAuditInformation(PaginationRequest paginationInfo)
{ {
using (var ctx = _contextFactory.CreateContext(enableTracking: false)) await using var ctx = _contextFactory.CreateContext(enableTracking: false);
{
var iqItems = (from change in ctx.EFChangeHistory var iqItems = (from change in ctx.EFChangeHistory
where change.TypeOfChange != Database.Models.EFChangeHistory.ChangeType.Ban where change.TypeOfChange != Database.Models.EFChangeHistory.ChangeType.Ban
orderby change.TimeChanged descending orderby change.TimeChanged descending
@ -52,4 +51,3 @@ namespace SharedLibraryCore.Repositories
} }
} }
} }
}