diff --git a/crates/codegen/src/csharp.rs b/crates/codegen/src/csharp.rs index 946eccc82af..2084b0c9844 100644 --- a/crates/codegen/src/csharp.rs +++ b/crates/codegen/src/csharp.rs @@ -789,6 +789,10 @@ impl Lang for Csharp<'_> { "\"{reducer_str_name}\" => BSATNHelpers.Decode(encodedArgs)," ); } + writeln!( + output, + r#""" => throw new SpacetimeDBEmptyReducerNameException("Reducer name is empty"),"# + ); writeln!( output, r#"var reducer => throw new ArgumentOutOfRangeException("Reducer", $"Unknown reducer {{reducer}}")"# diff --git a/crates/codegen/tests/snapshots/codegen__codegen_csharp.snap b/crates/codegen/tests/snapshots/codegen__codegen_csharp.snap index 0937300d1a7..77755cee286 100644 --- a/crates/codegen/tests/snapshots/codegen__codegen_csharp.snap +++ b/crates/codegen/tests/snapshots/codegen__codegen_csharp.snap @@ -1,5 +1,6 @@ --- source: crates/codegen/tests/codegen.rs +assertion_line: 37 expression: outfiles --- "Reducers/Add.g.cs" = ''' @@ -1463,6 +1464,7 @@ namespace SpacetimeDB "say_hello" => BSATNHelpers.Decode(encodedArgs), "test" => BSATNHelpers.Decode(encodedArgs), "test_btree_index_args" => BSATNHelpers.Decode(encodedArgs), + "" => throw new SpacetimeDBEmptyReducerNameException("Reducer name is empty"), var reducer => throw new ArgumentOutOfRangeException("Reducer", $"Unknown reducer {reducer}") }; } diff --git a/demo/Blackholio/client-unity/Assets/Scripts/autogen/SpacetimeDBClient.g.cs b/demo/Blackholio/client-unity/Assets/Scripts/autogen/SpacetimeDBClient.g.cs index 2096f4ad972..8ddfb8ad3d7 100644 --- a/demo/Blackholio/client-unity/Assets/Scripts/autogen/SpacetimeDBClient.g.cs +++ b/demo/Blackholio/client-unity/Assets/Scripts/autogen/SpacetimeDBClient.g.cs @@ -491,6 +491,7 @@ protected override Reducer ToReducer(TransactionUpdate update) "spawn_food" => BSATNHelpers.Decode(encodedArgs), "suicide" => BSATNHelpers.Decode(encodedArgs), "update_player_input" => BSATNHelpers.Decode(encodedArgs), + "" => throw new SpacetimeDBEmptyReducerNameException("Reducer name is empty"), var reducer => throw new ArgumentOutOfRangeException("Reducer", $"Unknown reducer {reducer}") }; } diff --git a/sdks/csharp/examples~/quickstart-chat/client/module_bindings/SpacetimeDBClient.g.cs b/sdks/csharp/examples~/quickstart-chat/client/module_bindings/SpacetimeDBClient.g.cs index 685ef94b90d..3ec6b5b9825 100644 --- a/sdks/csharp/examples~/quickstart-chat/client/module_bindings/SpacetimeDBClient.g.cs +++ b/sdks/csharp/examples~/quickstart-chat/client/module_bindings/SpacetimeDBClient.g.cs @@ -472,6 +472,7 @@ protected override Reducer ToReducer(TransactionUpdate update) "ClientDisconnected" => BSATNHelpers.Decode(encodedArgs), "SendMessage" => BSATNHelpers.Decode(encodedArgs), "SetName" => BSATNHelpers.Decode(encodedArgs), + "" => throw new SpacetimeDBEmptyReducerNameException("Reducer name is empty"), var reducer => throw new ArgumentOutOfRangeException("Reducer", $"Unknown reducer {reducer}") }; } diff --git a/sdks/csharp/examples~/regression-tests/client/module_bindings/SpacetimeDBClient.g.cs b/sdks/csharp/examples~/regression-tests/client/module_bindings/SpacetimeDBClient.g.cs index 1da912a8d6e..7c0795d0624 100644 --- a/sdks/csharp/examples~/regression-tests/client/module_bindings/SpacetimeDBClient.g.cs +++ b/sdks/csharp/examples~/regression-tests/client/module_bindings/SpacetimeDBClient.g.cs @@ -470,6 +470,7 @@ protected override Reducer ToReducer(TransactionUpdate update) "Add" => BSATNHelpers.Decode(encodedArgs), "Delete" => BSATNHelpers.Decode(encodedArgs), "ThrowError" => BSATNHelpers.Decode(encodedArgs), + "" => throw new SpacetimeDBEmptyReducerNameException("Reducer name is empty"), var reducer => throw new ArgumentOutOfRangeException("Reducer", $"Unknown reducer {reducer}") }; } diff --git a/sdks/csharp/examples~/regression-tests/republishing/client/client.csproj b/sdks/csharp/examples~/regression-tests/republishing/client/client.csproj index 3afdea6e783..759ea6f4a26 100644 --- a/sdks/csharp/examples~/regression-tests/republishing/client/client.csproj +++ b/sdks/csharp/examples~/regression-tests/republishing/client/client.csproj @@ -8,7 +8,7 @@ - + diff --git a/sdks/csharp/examples~/regression-tests/republishing/client/module_bindings/SpacetimeDBClient.g.cs b/sdks/csharp/examples~/regression-tests/republishing/client/module_bindings/SpacetimeDBClient.g.cs index 81551e7d410..2eae003de0e 100644 --- a/sdks/csharp/examples~/regression-tests/republishing/client/module_bindings/SpacetimeDBClient.g.cs +++ b/sdks/csharp/examples~/regression-tests/republishing/client/module_bindings/SpacetimeDBClient.g.cs @@ -468,6 +468,7 @@ protected override Reducer ToReducer(TransactionUpdate update) return update.ReducerCall.ReducerName switch { "Insert" => BSATNHelpers.Decode(encodedArgs), + "" => throw new SpacetimeDBEmptyReducerNameException("Reducer name is empty"), var reducer => throw new ArgumentOutOfRangeException("Reducer", $"Unknown reducer {reducer}") }; } diff --git a/sdks/csharp/src/Exceptions.cs b/sdks/csharp/src/Exceptions.cs new file mode 100644 index 00000000000..c08f3a00b61 --- /dev/null +++ b/sdks/csharp/src/Exceptions.cs @@ -0,0 +1,138 @@ +using System; +using System.Runtime.Serialization; + +namespace SpacetimeDB +{ + /// + /// The base class for all SpacetimeDB SDK exceptions. + /// This allows users to catch all SpacetimeDB-specific exceptions in one catch block + /// or configure their debugger to ignore them. + /// + [Serializable] + public class SpacetimeDBException : Exception + { + // Base HRESULT for SpacetimeDB exceptions (0x8A000000 is in the user-defined range) + private const int SPACETIMEDB_HRESULT_BASE = unchecked((int)0x8A000000); + + // Specific HRESULTs for different exception types + public const int SPACETIMEDB_EMPTY_REDUCER_NAME = SPACETIMEDB_HRESULT_BASE + 1; + + public SpacetimeDBException() + : base() + { + HResult = SPACETIMEDB_HRESULT_BASE; + } + + public SpacetimeDBException(string? message) + : base(message) + { + HResult = SPACETIMEDB_HRESULT_BASE; + } + + public SpacetimeDBException(string? message, Exception? innerException) + : base(message, innerException) + { + HResult = SPACETIMEDB_HRESULT_BASE; + } + + protected SpacetimeDBException(SerializationInfo info, StreamingContext context) + : base(info, context) { } + } + + /// + /// The exception that is thrown when one of the arguments provided to a method is not valid. + /// This is the base class for all SpacetimeDB argument exceptions. + /// + [Serializable] + public class SpacetimeDBArgumentException : SpacetimeDBException + { + private readonly string? _paramName; + + public SpacetimeDBArgumentException() + : base("Value does not fall within the expected range.") { } + + public SpacetimeDBArgumentException(string? message) + : base(message) { } + + public SpacetimeDBArgumentException(string? message, Exception? innerException) + : base(message, innerException) { } + + public SpacetimeDBArgumentException( + string? message, + string? paramName, + Exception? innerException + ) + : base(message, innerException) + { + _paramName = paramName; + } + + public SpacetimeDBArgumentException(string? message, string? paramName) + : base(message) + { + _paramName = paramName; + } + + protected SpacetimeDBArgumentException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + _paramName = info.GetString("ParamName"); + } + + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue("ParamName", _paramName, typeof(string)); + } + + public virtual string? ParamName => _paramName; + } + + /// + /// The exception that is thrown when an empty reducer name is received from the server. + /// This is a known condition that is handled internally by the SpacetimeDB client. + /// + [Serializable] + public class SpacetimeDBEmptyReducerNameException : SpacetimeDBArgumentException + { + public SpacetimeDBEmptyReducerNameException() + : base("Empty reducer name received from server", (string?)null) + { + HResult = SPACETIMEDB_EMPTY_REDUCER_NAME; + } + + public SpacetimeDBEmptyReducerNameException(string? paramName) + : base("Empty reducer name received from server", paramName) + { + HResult = SPACETIMEDB_EMPTY_REDUCER_NAME; + } + + public SpacetimeDBEmptyReducerNameException(string? message, string? paramName) + : base(message, paramName) + { + HResult = SPACETIMEDB_EMPTY_REDUCER_NAME; + } + + public SpacetimeDBEmptyReducerNameException(string? message, Exception? innerException) + : base(message, null, innerException) + { + HResult = SPACETIMEDB_EMPTY_REDUCER_NAME; + } + + public SpacetimeDBEmptyReducerNameException( + string? message, + string? paramName, + Exception? innerException + ) + : base(message, paramName, innerException) + { + HResult = SPACETIMEDB_EMPTY_REDUCER_NAME; + } + + protected SpacetimeDBEmptyReducerNameException( + SerializationInfo info, + StreamingContext context + ) + : base(info, context) { } + } +} diff --git a/sdks/csharp/src/Exceptions.cs.meta b/sdks/csharp/src/Exceptions.cs.meta new file mode 100644 index 00000000000..fb8de1e45f6 --- /dev/null +++ b/sdks/csharp/src/Exceptions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d588ff775ddb1d8449a250087d08f907 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: