only unload plugins once at shutdown
clean up some doc warnings
This commit is contained in:
parent
c93f896bc5
commit
a863f78678
@ -587,16 +587,29 @@ namespace IW4MAdmin.Application
|
|||||||
|
|
||||||
public async Task Start() => await UpdateServerStates();
|
public async Task Start() => await UpdateServerStates();
|
||||||
|
|
||||||
public void Stop()
|
public async Task Stop()
|
||||||
{
|
{
|
||||||
_tokenSource.Cancel();
|
_tokenSource.Cancel();
|
||||||
|
|
||||||
|
foreach (var plugin in Plugins)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await plugin.OnUnloadAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Could not cleanly unload plugin {PluginName}", plugin.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
IsRunning = false;
|
IsRunning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Restart()
|
public void Restart()
|
||||||
{
|
{
|
||||||
IsRestartRequested = true;
|
IsRestartRequested = true;
|
||||||
Stop();
|
Stop().GetAwaiter().GetResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete]
|
[Obsolete]
|
||||||
|
@ -903,11 +903,6 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
await e.WaitAsync(Utilities.DefaultCommandTimeout, new CancellationTokenRegistration().Token);
|
await e.WaitAsync(Utilities.DefaultCommandTimeout, new CancellationTokenRegistration().Token);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var plugin in Manager.Plugins)
|
|
||||||
{
|
|
||||||
await plugin.OnUnloadAsync();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DateTime start = DateTime.Now;
|
DateTime start = DateTime.Now;
|
||||||
|
@ -77,8 +77,12 @@ namespace IW4MAdmin.Application
|
|||||||
/// <param name="e"></param>
|
/// <param name="e"></param>
|
||||||
private static async void OnCancelKey(object sender, ConsoleCancelEventArgs e)
|
private static async void OnCancelKey(object sender, ConsoleCancelEventArgs e)
|
||||||
{
|
{
|
||||||
_serverManager?.Stop();
|
if (_serverManager is not null)
|
||||||
if (_applicationTask != null)
|
{
|
||||||
|
await _serverManager.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_applicationTask is not null)
|
||||||
{
|
{
|
||||||
await _applicationTask;
|
await _applicationTask;
|
||||||
}
|
}
|
||||||
@ -153,8 +157,11 @@ namespace IW4MAdmin.Application
|
|||||||
{
|
{
|
||||||
Console.WriteLine(e.Message);
|
Console.WriteLine(e.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
_serverManager?.Stop();
|
if (_serverManager is not null)
|
||||||
|
{
|
||||||
|
await _serverManager?.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
Console.WriteLine(exitMessage);
|
Console.WriteLine(exitMessage);
|
||||||
await Console.In.ReadAsync(new char[1], 0, 1);
|
await Console.In.ReadAsync(new char[1], 0, 1);
|
||||||
|
@ -33,10 +33,9 @@ namespace SharedLibraryCore.Commands
|
|||||||
RequiresTarget = false;
|
RequiresTarget = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task ExecuteAsync(GameEvent E)
|
public override async Task ExecuteAsync(GameEvent E)
|
||||||
{
|
{
|
||||||
E.Owner.Manager.Stop();
|
await E.Owner.Manager.Stop();
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -731,7 +730,7 @@ namespace SharedLibraryCore.Commands
|
|||||||
var ruleFormat = rules.Select(r => $"- {r}");
|
var ruleFormat = rules.Select(r => $"- {r}");
|
||||||
if (gameEvent.Message.IsBroadcastCommand(_config.BroadcastCommandPrefix))
|
if (gameEvent.Message.IsBroadcastCommand(_config.BroadcastCommandPrefix))
|
||||||
{
|
{
|
||||||
gameEvent.Owner.Broadcast(ruleFormat);
|
await gameEvent.Owner.BroadcastAsync(ruleFormat, token: gameEvent.Owner.Manager.CancellationToken);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -8,6 +8,7 @@ namespace SharedLibraryCore.Helpers
|
|||||||
/// Generate password hash and salt
|
/// Generate password hash and salt
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="password">plaintext password</param>
|
/// <param name="password">plaintext password</param>
|
||||||
|
/// <param name="saltStr">salt of password</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string[] Hash(string password, string saltStr = null)
|
public static string[] Hash(string password, string saltStr = null)
|
||||||
{
|
{
|
||||||
@ -35,4 +36,4 @@ namespace SharedLibraryCore.Helpers
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
ConcurrentDictionary<long, GameEvent> ProcessingEvents { get; }
|
ConcurrentDictionary<long, GameEvent> ProcessingEvents { get; }
|
||||||
Task Init();
|
Task Init();
|
||||||
Task Start();
|
Task Start();
|
||||||
void Stop();
|
Task Stop();
|
||||||
void Restart();
|
void Restart();
|
||||||
|
|
||||||
[Obsolete]
|
[Obsolete]
|
||||||
@ -103,4 +103,4 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
event EventHandler<GameEvent> OnGameEventExecuted;
|
event EventHandler<GameEvent> OnGameEventExecuted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
/// <param name="metaKey">key of meta data</param>
|
/// <param name="metaKey">key of meta data</param>
|
||||||
/// <param name="metaValue">value of the meta data</param>
|
/// <param name="metaValue">value of the meta data</param>
|
||||||
/// <param name="client">client to save the meta for</param>
|
/// <param name="client">client to save the meta for</param>
|
||||||
|
/// <param name="linkedMeta"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task AddPersistentMeta(string metaKey, string metaValue, EFClient client, EFMeta linkedMeta = null);
|
Task AddPersistentMeta(string metaKey, string metaValue, EFClient client, EFMeta linkedMeta = null);
|
||||||
|
|
||||||
|
@ -42,7 +42,6 @@ public interface IMetaServiceV2
|
|||||||
/// <param name="lookupId">Id in the list of lookup values</param>
|
/// <param name="lookupId">Id in the list of lookup values</param>
|
||||||
/// <param name="clientId">id of the client</param>
|
/// <param name="clientId">id of the client</param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task SetPersistentMetaForLookupKey(string metaKey, string lookupKey, int lookupId, int clientId,
|
Task SetPersistentMetaForLookupKey(string metaKey, string lookupKey, int lookupId, int clientId,
|
||||||
CancellationToken token = default);
|
CancellationToken token = default);
|
||||||
@ -100,7 +99,6 @@ public interface IMetaServiceV2
|
|||||||
/// <param name="lookupKey"></param>
|
/// <param name="lookupKey"></param>
|
||||||
/// <param name="clientId"></param>
|
/// <param name="clientId"></param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<EFMeta> GetPersistentMetaByLookup(string metaKey, string lookupKey, int clientId,
|
Task<EFMeta> GetPersistentMetaByLookup(string metaKey, string lookupKey, int clientId,
|
||||||
CancellationToken token = default);
|
CancellationToken token = default);
|
||||||
@ -141,7 +139,6 @@ public interface IMetaServiceV2
|
|||||||
/// removes meta key with given value
|
/// removes meta key with given value
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="metaKey">key of the meta data</param>
|
/// <param name="metaKey">key of the meta data</param>
|
||||||
/// <param name="metaValue">value of the meta data</param>
|
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task RemovePersistentMeta(string metaKey, CancellationToken token = default);
|
Task RemovePersistentMeta(string metaKey, CancellationToken token = default);
|
||||||
|
@ -14,6 +14,7 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">type of RCon query to perform</param>
|
/// <param name="type">type of RCon query to perform</param>
|
||||||
/// <param name="parameters">optional parameter list</param>
|
/// <param name="parameters">optional parameter list</param>
|
||||||
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<string[]> SendQueryAsync(StaticHelpers.QueryType type, string parameters = "", CancellationToken token = default);
|
Task<string[]> SendQueryAsync(StaticHelpers.QueryType type, string parameters = "", CancellationToken token = default);
|
||||||
|
|
||||||
|
@ -52,6 +52,7 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
/// <param name="connection">RCon connection to retrieve with</param>
|
/// <param name="connection">RCon connection to retrieve with</param>
|
||||||
/// <param name="dvarName">name of DVAR</param>
|
/// <param name="dvarName">name of DVAR</param>
|
||||||
/// <param name="fallbackValue">default value to return if dvar retrieval fails</param>
|
/// <param name="fallbackValue">default value to return if dvar retrieval fails</param>
|
||||||
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<Dvar<T>> GetDvarAsync<T>(IRConConnection connection, string dvarName, T fallbackValue = default, CancellationToken token = default);
|
Task<Dvar<T>> GetDvarAsync<T>(IRConConnection connection, string dvarName, T fallbackValue = default, CancellationToken token = default);
|
||||||
|
|
||||||
@ -61,6 +62,7 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
/// <param name="connection">RCon connection to use</param>
|
/// <param name="connection">RCon connection to use</param>
|
||||||
/// <param name="dvarName">name of DVAR to set</param>
|
/// <param name="dvarName">name of DVAR to set</param>
|
||||||
/// <param name="dvarValue">value to set DVAR to</param>
|
/// <param name="dvarValue">value to set DVAR to</param>
|
||||||
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<bool> SetDvarAsync(IRConConnection connection, string dvarName, object dvarValue, CancellationToken token = default);
|
Task<bool> SetDvarAsync(IRConConnection connection, string dvarName, object dvarValue, CancellationToken token = default);
|
||||||
|
|
||||||
@ -69,13 +71,15 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="connection">RCon connection to use</param>
|
/// <param name="connection">RCon connection to use</param>
|
||||||
/// <param name="command">console command to execute</param>
|
/// <param name="command">console command to execute</param>
|
||||||
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<string[]> ExecuteCommandAsync(IRConConnection connection, string command, CancellationToken token = default);
|
Task<string[]> ExecuteCommandAsync(IRConConnection connection, string command, CancellationToken token = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// get the list of connected clients from status response
|
/// get the list of connected clients from status response
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="connection">RCon connection to use</param>
|
/// <param name="connection">RCon connection to use</param>
|
||||||
|
/// <param name="token"></param>
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// <see cref="IStatusResponse" />
|
/// <see cref="IStatusResponse" />
|
||||||
/// </returns>
|
/// </returns>
|
||||||
|
@ -16,8 +16,8 @@
|
|||||||
/// resolves a service with the given name and generic params
|
/// resolves a service with the given name and generic params
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="serviceName">class name of service</param>
|
/// <param name="serviceName">class name of service</param>
|
||||||
/// <param name="genericParams">generic class names</param>
|
/// <param name="genericParameters">generic class names</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
object ResolveService(string serviceName, string[] genericParameters);
|
object ResolveService(string serviceName, string[] genericParameters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,9 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// authorizes given token
|
/// authorizes given token
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="networkId">network id of the client to authorize</param>
|
||||||
/// <param name="token">token to authorize</param>
|
/// <param name="token">token to authorize</param>
|
||||||
/// <returns>true if token authorized successfully, false otherwise</returns>
|
/// <returns>true if token authorized successfully, false otherwise</returns>
|
||||||
bool AuthorizeToken(long networkId, string token);
|
bool AuthorizeToken(long networkId, string token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -307,6 +307,7 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="flagReason">reason for flagging</param>
|
/// <param name="flagReason">reason for flagging</param>
|
||||||
/// <param name="sender">client performing the flag</param>
|
/// <param name="sender">client performing the flag</param>
|
||||||
|
/// <param name="flagLength">how long the flag should last</param>
|
||||||
/// <returns>game event for the flag</returns>
|
/// <returns>game event for the flag</returns>
|
||||||
public GameEvent Flag(string flagReason, EFClient sender, TimeSpan? flagLength = null)
|
public GameEvent Flag(string flagReason, EFClient sender, TimeSpan? flagLength = null)
|
||||||
{
|
{
|
||||||
@ -442,6 +443,7 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="banReason">reason for the ban</param>
|
/// <param name="banReason">reason for the ban</param>
|
||||||
/// <param name="sender">client performing the ban</param>
|
/// <param name="sender">client performing the ban</param>
|
||||||
|
/// <param name="isEvade">obsolete</param>
|
||||||
public GameEvent Ban(string banReason, EFClient sender, bool isEvade)
|
public GameEvent Ban(string banReason, EFClient sender, bool isEvade)
|
||||||
{
|
{
|
||||||
var e = new GameEvent
|
var e = new GameEvent
|
||||||
|
@ -159,14 +159,13 @@ namespace SharedLibraryCore
|
|||||||
/// Add a player to the server's player list
|
/// Add a player to the server's player list
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="P">EFClient pulled from memory reading</param>
|
/// <param name="P">EFClient pulled from memory reading</param>
|
||||||
/// <returns>True if player added sucessfully, false otherwise</returns>
|
/// <returns>True if player added successfully, false otherwise</returns>
|
||||||
public abstract Task<EFClient> OnClientConnected(EFClient P);
|
public abstract Task<EFClient> OnClientConnected(EFClient P);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Remove player by client number
|
/// Remove player by client number
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="cNum">Client ID of player to be removed</param>
|
/// <returns>true if removal succeeded, false otherwise</returns>
|
||||||
/// <returns>true if removal succeded, false otherwise</returns>
|
|
||||||
public abstract Task OnClientDisconnected(EFClient client);
|
public abstract Task OnClientDisconnected(EFClient client);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -219,6 +218,7 @@ namespace SharedLibraryCore
|
|||||||
/// Send a message to all players
|
/// Send a message to all players
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message">Message to be sent to all players</param>
|
/// <param name="message">Message to be sent to all players</param>
|
||||||
|
/// <param name="sender">Client that initiated the broadcast</param>
|
||||||
public GameEvent Broadcast(string message, EFClient sender = null)
|
public GameEvent Broadcast(string message, EFClient sender = null)
|
||||||
{
|
{
|
||||||
var formattedMessage = string.Format(RconParser.Configuration.CommandPrefixes.Say ?? "",
|
var formattedMessage = string.Format(RconParser.Configuration.CommandPrefixes.Say ?? "",
|
||||||
@ -322,39 +322,44 @@ namespace SharedLibraryCore
|
|||||||
/// Kick a player from the server
|
/// Kick a player from the server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="reason">Reason for kicking</param>
|
/// <param name="reason">Reason for kicking</param>
|
||||||
/// <param name="Target">EFClient to kick</param>
|
/// <param name="target">EFClient to kick</param>
|
||||||
public Task Kick(string reason, EFClient Target, EFClient Origin)
|
/// <param name="origin">Client initating the kick</param>
|
||||||
|
public Task Kick(string reason, EFClient target, EFClient origin)
|
||||||
{
|
{
|
||||||
return Kick(reason, Target, Origin, null);
|
return Kick(reason, target, origin, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Temporarily ban a player ( default 1 hour ) from the server
|
/// Temporarily ban a player ( default 1 hour ) from the server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="reason">Reason for banning the player</param>
|
/// <param name="reason">Reason for banning the player</param>
|
||||||
/// <param name="Target">The player to ban</param>
|
/// <param name="length">Duration of the ban</param>
|
||||||
public abstract Task TempBan(string reason, TimeSpan length, EFClient Target, EFClient Origin);
|
/// <param name="target">The client to ban</param>
|
||||||
|
/// <param name="origin">The client performing the ban</param>
|
||||||
|
public abstract Task TempBan(string reason, TimeSpan length, EFClient target, EFClient origin);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Perm ban a player from the server
|
/// Perm ban a player from the server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="Reason">The reason for the ban</param>
|
/// <param name="reason">The reason for the ban</param>
|
||||||
/// <param name="Target">The person to ban</param>
|
/// <param name="target">The person to ban</param>
|
||||||
/// <param name="Origin">The person who banned the target</param>
|
/// <param name="origin">The person who banned the target</param>
|
||||||
public abstract Task Ban(string Reason, EFClient Target, EFClient Origin, bool isEvade = false);
|
/// <param name="isEvade">obsolete</param>
|
||||||
|
public abstract Task Ban(string reason, EFClient target, EFClient origin, bool isEvade = false);
|
||||||
|
|
||||||
public abstract Task Warn(string Reason, EFClient Target, EFClient Origin);
|
public abstract Task Warn(string reason, EFClient target, EFClient origin);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unban a player by npID / GUID
|
/// Unban a player by npID / GUID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="npID">npID of the player</param>
|
/// <param name="reason">reason for unban</param>
|
||||||
/// <param name="targetClient">I don't remember what this is for</param>
|
/// <param name="targetClient">client being unbanned</param>
|
||||||
|
/// <param name="originClient">client performing the unban</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public abstract Task Unban(string reason, EFClient targetClient, EFClient originClient);
|
public abstract Task Unban(string reason, EFClient targetClient, EFClient originClient);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Change the current searver map
|
/// Change the current server map
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="mapName">Non-localized map name</param>
|
/// <param name="mapName">Non-localized map name</param>
|
||||||
public async Task LoadMap(string mapName)
|
public async Task LoadMap(string mapName)
|
||||||
|
@ -593,7 +593,6 @@ namespace SharedLibraryCore.Services
|
|||||||
/// <param name="newPermission"></param>
|
/// <param name="newPermission"></param>
|
||||||
/// <param name="temporalClient"></param>
|
/// <param name="temporalClient"></param>
|
||||||
/// <param name="origin"></param>
|
/// <param name="origin"></param>
|
||||||
/// <param name="ctx"></param>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public virtual async Task UpdateLevel(Permission newPermission, EFClient temporalClient, EFClient origin)
|
public virtual async Task UpdateLevel(Permission newPermission, EFClient temporalClient, EFClient origin)
|
||||||
{
|
{
|
||||||
|
@ -121,7 +121,9 @@ namespace WebfrontCore
|
|||||||
services.AddSingleton(Program.ApplicationServiceProvider.GetRequiredService<IAuditInformationRepository>());
|
services.AddSingleton(Program.ApplicationServiceProvider.GetRequiredService<IAuditInformationRepository>());
|
||||||
services.AddSingleton(Program.ApplicationServiceProvider.GetRequiredService<ITranslationLookup>());
|
services.AddSingleton(Program.ApplicationServiceProvider.GetRequiredService<ITranslationLookup>());
|
||||||
services.AddSingleton(Program.ApplicationServiceProvider.GetRequiredService<IEnumerable<IManagerCommand>>());
|
services.AddSingleton(Program.ApplicationServiceProvider.GetRequiredService<IEnumerable<IManagerCommand>>());
|
||||||
|
#pragma warning disable CS0618
|
||||||
services.AddSingleton(Program.ApplicationServiceProvider.GetRequiredService<IMetaService>());
|
services.AddSingleton(Program.ApplicationServiceProvider.GetRequiredService<IMetaService>());
|
||||||
|
#pragma warning restore CS0618
|
||||||
services.AddSingleton(Program.ApplicationServiceProvider.GetRequiredService<IMetaServiceV2>());
|
services.AddSingleton(Program.ApplicationServiceProvider.GetRequiredService<IMetaServiceV2>());
|
||||||
services.AddSingleton(Program.ApplicationServiceProvider.GetRequiredService<ApplicationConfiguration>());
|
services.AddSingleton(Program.ApplicationServiceProvider.GetRequiredService<ApplicationConfiguration>());
|
||||||
services.AddSingleton(Program.ApplicationServiceProvider.GetRequiredService<ClientService>());
|
services.AddSingleton(Program.ApplicationServiceProvider.GetRequiredService<ClientService>());
|
||||||
|
Loading…
Reference in New Issue
Block a user