Actions
SapphireDb comes with an alternative for controllers. They are called ActionHandler
. You can use them like controllers in Asp.Net. You can define public methods that are exposed through the sapphire interfaces.
Basic example
Just create a class in your project and derive it from
You can use dependency injection in the constructor of the class.
The methods allow any serializable return type and you can also use async methods.
ActionHandlerBase
.You can use dependency injection in the constructor of the class.
The methods allow any serializable return type and you can also use async methods.
Calling the methods on client side is pretty easy. Just pass the name of the handler as first parameter and the name of the method as second.
Every other parameters will be used as parameters for the method.
Every other parameters will be used as parameters for the method.
\f:(typescript:Angular) this.db.execute('example.MethodWithParameters', 'parameter1', 'parameter2')\n \t.subscribe(console.log); \f:(csharp:ExampleActions.cs:Server) public class ExampleActions : ActionHandlerBase\n {\n \tprivate readonly ExampleDb db;\n\n \tpublic ExampleActions(ExampleDb db)\n \t{\n \tthis.db = db;\n \t}\n\n \tpublic string MethodWithParameters(string param1, string param2)\n \t{\n \t\treturn param1 + param2;\n \t}\n }
Stream data from server
You can also stream async data from server to client.
\f:(typescript:Angular) this.db.execute('example.AsyncEnumerableTest').subscribe(\n \tActionHelper.result(\n \t\t() => console.log('complete'),\n \t\t(value) => console.log(value),\n \t\t(notification) => console.warn(notification)\n \t));\n );\n\n // The code of the above example\n const result$ = this.db.execute<number, string>('example.AsyncEnumerableTest').pipe(\n \tshareReplay()\n );\n\n this.rangeValueStream$ = result$.pipe(\n \tfilter(v => v.type === ExecuteResponseType.Async),\n \tmap(v => v.result)\n );\n\n this.rangeValueStatus$ = result$.pipe(\n \tfilter(v => v.type === ExecuteResponseType.Notify),\n \tmap(v => v.notification)\n ); \f:(csharp:AsyncActions.cs:Server) public class AsyncActions : ActionHandlerBase\n {\n \tpublic async IAsyncEnumerable<string> AsyncEnumerableTest()\n \t{\n \t\tfor (int i = 0; i <= 100; i++)\n \t\t{\n \t\t\tyield return i.ToString();\n\n \t\t\tif (i % 10 == 0)\n \t\t\t{\n \t\t\t\tNotify("Progress: " + i + "%");\n \t\t\t}\n\n \t\t\tawait Task.Delay(10);\n \t\t}\n \t}\n }
Stream data to server (and back to client)
Streaming data from client to server is also possible. It is also possible to do both.
\f:(typescript:Angular) const subject$ = new ReplaySubject<string>();\n this.streamValueResponse$ = this.db.execute<string>('example.StreamTest', subject$);\n subject$.next('value');\n subject$.complete(); \f:(csharp:AsyncActions.cs:Server) public class AsyncActions : ActionHandlerBase\n {\n \tpublic async IAsyncEnumerable<string> StreamTest(IAsyncEnumerable<string> inputStream)\n \t{\n \t\tawait foreach (string input in inputStream)\n \t\t{\n \t\t\tyield return input + " from server";\n \t\t}\n \t}\n }
Notifications
Because SapphireDb allows a bidirectional communication between client and server you can also send additional notifications during method execution. This is useful to transfer a state for example.
Use the
Use the
Notify
-method in your action handler to achieve that.
The client side can use the action helper to distinguish between notification and final result.
\f:(typescript:Angular) this.db.execute('example.MethodWithParameters', 'parameter1', 'parameter2')\n \t.subscribe(ActionHelper.result<string, number>(\n \t\t(result) => {\n \t\t\talert(result);\n \t\t},\n \t\t(notification) => {\n \t\t\tconsole.log(notification);\n \t\t}\n \t)\n ); \f:(csharp:AsyncActions.cs:Server) public class AsyncActions : ActionHandlerBase\n {\n \tpublic async Task<string> AsyncDelay()\n \t{\n \t\tfor (int i = 0; i <= 100; i++)\n \t\t{\n \t\t\tawait Task.Delay(10);\n \t\t\tNotify(i);\n \t\t}\n\n \t\treturn "complete";\n \t}\n }