diff --git a/src/Directory.Build.props b/src/Directory.Build.props
new file mode 100644
index 0000000..f2b2cc2
--- /dev/null
+++ b/src/Directory.Build.props
@@ -0,0 +1,46 @@
+
+
+
+ 6
+
+ CS1591;CA5349
+ disable
+ enable
+ true
+ true
+ true
+ True
+ true
+ true
+ latest
+ All
+ true
+ 4DotNet
+ Whack-A-Mole Core Library
+ 4Dotnet Whack-A-Mole Team
+ (c) 2024 - rights reserved
+ WAM.Core
+ Whack-a-mole core
+ 1.0.0
+ 12
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props
new file mode 100644
index 0000000..03b69b2
--- /dev/null
+++ b/src/Directory.Packages.props
@@ -0,0 +1,66 @@
+
+
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
+
+
\ No newline at end of file
diff --git a/src/Wam.Core/Configuration/AzureServices.cs b/src/Wam.Core/Configuration/AzureServices.cs
index 12ae27a..f3b7ca8 100644
--- a/src/Wam.Core/Configuration/AzureServices.cs
+++ b/src/Wam.Core/Configuration/AzureServices.cs
@@ -3,8 +3,8 @@
public class AzureServices
{
public const string SectionName = "AzureServices";
- public string WebPubSubEndpoint { get; set; }
- public string WebPubSubHub{ get; set; }
- public string UsersStorageAccountName { get; set; }
- public string GamesStorageAccountName { get; set; }
+ public string? WebPubSubEndpoint { get; set; }
+ public string? WebPubSubHub{ get; set; }
+ public string? UsersStorageAccountName { get; set; }
+ public string? GamesStorageAccountName { get; set; }
}
\ No newline at end of file
diff --git a/src/Wam.Core/Configuration/ServiceCollectionExtensions.cs b/src/Wam.Core/Configuration/ServiceCollectionExtensions.cs
index 29ce3ed..8cc0e9b 100644
--- a/src/Wam.Core/Configuration/ServiceCollectionExtensions.cs
+++ b/src/Wam.Core/Configuration/ServiceCollectionExtensions.cs
@@ -2,28 +2,39 @@
using Microsoft.Extensions.Azure;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
+using System.Diagnostics.CodeAnalysis;
using Wam.Core.Identity;
namespace Wam.Core.Configuration;
public static class ServiceCollectionExtensions
{
+ private const string MissingConfigMessage = "Missing Azure Services configuration";
+
public static IServiceCollection AddWamCoreConfiguration(
this IServiceCollection services,
- IConfiguration configuration,
+ [NotNull] IConfiguration configuration,
bool skipApplicationInsights = false)
{
- var azureServicesOptions = configuration.GetSection(AzureServices.SectionName).Get();
+ var azureServicesOptions = configuration
+ .GetSection(AzureServices.SectionName)
+ .Get()
+ ?? throw new InvalidOperationException(MissingConfigMessage);
+
services.AddHealthChecks();
- services.AddOptions().Bind(configuration.GetSection(AzureServices.SectionName)); //.ValidateOnStart();
- services.AddOptions().Bind(configuration.GetSection(ServicesConfiguration.SectionName)); //.ValidateOnStart();
+ services.AddOptions().Bind(configuration.GetSection(AzureServices.SectionName));
+ services.AddOptions().Bind(configuration.GetSection(ServicesConfiguration.SectionName));
+
+ string webPubSubEndpoint =
+ azureServicesOptions.WebPubSubEndpoint
+ ?? throw new InvalidOperationException(MissingConfigMessage);
services.AddAzureClients(builder =>
{
builder.AddWebPubSubServiceClient(
- new Uri(azureServicesOptions.WebPubSubEndpoint),
+ new Uri(webPubSubEndpoint),
azureServicesOptions.WebPubSubHub,
- CloudIdentity.GetCloudIdentity());
+ CloudIdentity.GetCloudIdentity);
});
if (!skipApplicationInsights)
diff --git a/src/Wam.Core/Enums/GameState.cs b/src/Wam.Core/Enums/GameState.cs
index 060b942..4fb14c1 100644
--- a/src/Wam.Core/Enums/GameState.cs
+++ b/src/Wam.Core/Enums/GameState.cs
@@ -4,45 +4,28 @@ namespace Wam.Core.Enums;
public abstract class GameState
{
-
- public static readonly GameState New;
- public static readonly GameState Current;
- public static readonly GameState Started;
- public static readonly GameState Finished;
- public static readonly GameState Cancelled;
- public static readonly GameState[] All;
+ public static readonly GameState Init = new GameStateInit();
+ public static readonly GameState Current = new GameStateCurrent();
+ public static readonly GameState Started = new GameStateStarted();
+ public static readonly GameState Finished = new GameStateFinished();
+ public static readonly GameState Cancelled = new GameStateCancelled();
+ public static readonly GameState[] All = [Init, Current, Started, Finished, Cancelled];
public static GameState FromCode(string code)
{
- var state = All.FirstOrDefault(s => s.Code == code);
- if (state == null)
- {
- throw new InvalidOperationException($"Invalid game state code {code}");
- }
- return state;
+ return Array.Find(All, s => s.Code == code)
+ ?? throw new InvalidOperationException($"Invalid game state code {code}");
}
public abstract string Code { get; }
public virtual string TranslationKey => $"Game.States.{Code}";
public virtual bool CanChangeTo(GameState state) => false;
-
- static GameState()
- {
- All = new[]
- {
- New = new GameStateNew() ,
- Current = new GameStateCurrent(),
- Started = new GameStateStarted(),
- Finished = new GameStateFinished(),
- Cancelled = new GameStateCancelled()
- };
- }
}
-public class GameStateNew : GameState
+public class GameStateInit : GameState
{
- public override string Code => "New";
+ public override string Code => "Init";
public override bool CanChangeTo(GameState state)
{
return state == Current || state == Cancelled;
diff --git a/src/Wam.Core/ErrorCodes/WamErrorCode.cs b/src/Wam.Core/ErrorCodes/WamErrorCode.cs
index fb366b4..bb8332a 100644
--- a/src/Wam.Core/ErrorCodes/WamErrorCode.cs
+++ b/src/Wam.Core/ErrorCodes/WamErrorCode.cs
@@ -2,9 +2,7 @@
public abstract class WamErrorCode
{
-
public abstract string Code { get; }
- public virtual string Namespace { get; } = "Wam.ErrorCodes";
- public virtual string TranslationKey => $"{Namespace}.{Code}";
-
-}
\ No newline at end of file
+ public virtual string RootNamespace { get; } = "Wam.ErrorCodes";
+ public virtual string TranslationKey => $"{RootNamespace}.{Code}";
+}
diff --git a/src/Wam.Core/Events/RealtimeEvent.cs b/src/Wam.Core/Events/RealtimeEvent.cs
index e39ad1a..3771055 100644
--- a/src/Wam.Core/Events/RealtimeEvent.cs
+++ b/src/Wam.Core/Events/RealtimeEvent.cs
@@ -5,8 +5,8 @@ namespace Wam.Core.Events;
public class RealtimeEvent
{
- public string Message { get; set; }
- public T Data { get; set; }
+ public string Message { get; set; } = string.Empty;
+ public T Data { get; set; } = default!;
public string ToJson()
{
@@ -19,6 +19,5 @@ public string ToJson()
ContractResolver = contractResolver,
Formatting = Formatting.None
});
-
}
}
\ No newline at end of file
diff --git a/src/Wam.Core/Exceptions/WamException.cs b/src/Wam.Core/Exceptions/WamException.cs
index 677955a..a7b5850 100644
--- a/src/Wam.Core/Exceptions/WamException.cs
+++ b/src/Wam.Core/Exceptions/WamException.cs
@@ -2,7 +2,20 @@
namespace Wam.Core.Exceptions;
-public class WamException(WamErrorCode error, string message) : Exception(message)
+public class WamException(WamErrorCode? error, string message, Exception? innerException) : Exception(message, innerException)
{
- public WamErrorCode Error { get; } = error;
+ private const string ErrorCodeIsMissingMessage = "WamErrorCode is required";
+ public WamErrorCode Error { get; } = error ?? throw new ArgumentNullException(nameof(error), ErrorCodeIsMissingMessage);
+
+ public WamException() : this(null, "An unknown error occurred.", null)
+ {
+ }
+
+ public WamException(string message) : this(null, message, null)
+ {
+ }
+
+ public WamException(string message, Exception innerException) : this(null, message, innerException)
+ {
+ }
}
\ No newline at end of file
diff --git a/src/Wam.Core/ExtensionMethods/ConfigurationExtensions.cs b/src/Wam.Core/ExtensionMethods/ConfigurationExtensions.cs
index ddfbf36..6556a31 100644
--- a/src/Wam.Core/ExtensionMethods/ConfigurationExtensions.cs
+++ b/src/Wam.Core/ExtensionMethods/ConfigurationExtensions.cs
@@ -6,12 +6,10 @@ public static class ConfigurationExtensions
{
public static string GetRequiredValue(this IConfiguration configuration, string key, string? description = null)
{
- string value = configuration.GetValue(key);
- if (string.IsNullOrWhiteSpace(value))
- {
- throw new InvalidOperationException("Missing setting " + ((description != null) ? ("for " + description) : "") + " : " + key);
- }
-
- return value;
+ return configuration.GetValue(key)
+ ?? throw new InvalidOperationException(
+ $"Missing setting {ForDescription(description)}: {key}");
}
+
+ private static string ForDescription(string? description) => (description != null) ? $"for {description} " : string.Empty;
}
\ No newline at end of file
diff --git a/src/Wam.Core/ExtensionMethods/IntegerExtensions.cs b/src/Wam.Core/ExtensionMethods/IntegerExtensions.cs
index 31e5cad..f4883e5 100644
--- a/src/Wam.Core/ExtensionMethods/IntegerExtensions.cs
+++ b/src/Wam.Core/ExtensionMethods/IntegerExtensions.cs
@@ -2,8 +2,6 @@
public static class IntegerExtensions
{
-
public static bool IsHttpSuccessCode(this int code)
=> code >= 200 && code <= 299;
-
}
\ No newline at end of file
diff --git a/src/Wam.Core/ExtensionMethods/StringExtensions.cs b/src/Wam.Core/ExtensionMethods/StringExtensions.cs
index 55b1121..a166baf 100644
--- a/src/Wam.Core/ExtensionMethods/StringExtensions.cs
+++ b/src/Wam.Core/ExtensionMethods/StringExtensions.cs
@@ -1,21 +1,17 @@
-namespace Wam.Core.ExtensionMethods;
+using System.Security.Cryptography;
+namespace Wam.Core.ExtensionMethods;
public static class StringExtensions
{
private const string Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
- private static readonly Random Random;
public static string GenerateGameCode(int length = 6)
{
var result = new string(
- Enumerable.Repeat(Chars, length)
- .Select(s => s[Random.Next(s.Length)])
- .ToArray());
+ Enumerable
+ .Repeat(Chars, length)
+ .Select(s => s[RandomNumberGenerator.GetInt32(s.Length)])
+ .ToArray());
return result;
}
-
- static StringExtensions()
- {
- Random = new Random();
- }
}
\ No newline at end of file
diff --git a/src/Wam.Core/Identity/CloudIdentity.cs b/src/Wam.Core/Identity/CloudIdentity.cs
index 4c603be..cdb5e00 100644
--- a/src/Wam.Core/Identity/CloudIdentity.cs
+++ b/src/Wam.Core/Identity/CloudIdentity.cs
@@ -3,13 +3,10 @@
namespace Wam.Core.Identity;
-public class CloudIdentity
+public static class CloudIdentity
{
- public static TokenCredential GetCloudIdentity()
- {
- return new ChainedTokenCredential(
+ public static TokenCredential GetCloudIdentity => new ChainedTokenCredential(
new ManagedIdentityCredential(),
new VisualStudioCredential(),
new AzureCliCredential());
- }
}
\ No newline at end of file
diff --git a/src/Wam.Core/Wam.Core.csproj b/src/Wam.Core/Wam.Core.csproj
index 1be4346..c194da5 100644
--- a/src/Wam.Core/Wam.Core.csproj
+++ b/src/Wam.Core/Wam.Core.csproj
@@ -12,17 +12,17 @@
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/wam-core-library.sln b/src/wam-core-library.sln
index a6b0b3c..b65ff86 100644
--- a/src/wam-core-library.sln
+++ b/src/wam-core-library.sln
@@ -3,7 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.6.33717.318
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wam.Core", "Wam.Core\Wam.Core.csproj", "{D5F4E98F-FFD3-4448-B17C-56AA61719D59}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wam.Core", "Wam.Core\Wam.Core.csproj", "{D5F4E98F-FFD3-4448-B17C-56AA61719D59}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F83C7DFC-90A3-4D64-98DE-C5F2156E7752}"
+ ProjectSection(SolutionItems) = preProject
+ Directory.Build.props = Directory.Build.props
+ Directory.Packages.props = Directory.Packages.props
+ EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution