Websocket Routes
To simplify WebSocket communication, AventusSharp provides a routing system similar to an HTTP router. This allows for easier message handling and response generation. To use this feature, create a class that inherits from WsRouter
. As with an HTTP router, public methods in this class are treated as WebSocket event handlers.
using AventusSharp.WebSocket;
namespace Demo.Websocket.Routes{ public class MainRouter : WsRouter { public string Index() { return "It's working"; } }}
With the above code, if you send a message to /
(an alias for Index
), the server will respond with the message: "It's working"
. By default, the response is sent only to the connection that initiated the request.
Return Types
The return type of a route determines the server’s response:
void
: If the method returnsvoid
, anEmptyEvent
is sent.WsEvent
: If the method returns aWsEvent
or a child, it is sent directly.- Other Objects: Any other object is serialized into JSON and sent as a
JsonEvent
.
using AventusSharp.WebSocket;using AventusSharp.WebSocket.Event;using Demo.Data;
namespace Demo.Websocket.Routes{ public class MainRouter : WsRouter { // /, returns a JsonEvent with a string public string Index() { return "It's working"; }
// /user, explicitly returns a JsonEvent with a User object public JsonEvent User() { return new JsonEvent(new User()); }
// /user2, implicitly returns a JsonEvent with a User object public User User2() { return new User(); } }}
Response Types
By default, only the connection that initiated the request receives the response. However, you can modify this behavior using attributes to specify different response types:
Built-in Response Attributes
[Broadcast]
: Sends the message to all open connections within the endpoint.[Others]
: Sends the message to all connections except the one that initiated the request.
Custom Response Logic
You can define custom response behavior by creating an attribute that inherits from Custom
.
using AventusSharp.WebSocket;using AventusSharp.WebSocket.Attributes;
public class UserBroadcast : Custom{ public override List<WebSocketConnection> GetConnections(WsEndPoint endPoint, WebSocketConnection? connection) { int userId = connection?.GetContext().GetUserId() ?? 0;
if (endPoint is MainEndPoint mainEndPoint && userId != 0) { return mainEndPoint.GetConnectionsByUser(userId); }
return new List<WebSocketConnection>(); }}
In this example, the UserBroadcast
attribute sends the message only to connections belonging to a specific user, based on the logic defined in the GetConnections
method.
Custom URL Definitions
Prefixing Routes
You can add a prefix to all routes within a router using the [Prefix(string)]
attribute. This helps in grouping related routes under a common path.
using AventusSharp.WebSocket;using AventusSharp.WebSocket.Attributes;
namespace Demo.Websocket.Routes{ [Prefix("Main")] public class MainRouter : WsRouter { // /main/ public string Index() { return "It's working"; } }}
Customizing Individual Route Paths
To rename individual routes, use the [Path(string)]
attribute. This allows you to define a unique path for each route.
// MainRouter.csusing AventusSharp.WebSocket;using AventusSharp.WebSocket.Attributes;using Path = AventusSharp.WebSocket.Attributes.Path;
namespace Demo.Websocket.Routes{ [Prefix("Main")] public class MainRouter : WsRouter { // /main/ public string Index() { return "It's working"; }
// /main/demo [Path("/Demo")] public string Test() { return "It's a test"; } }}
URL Parameters
You can add parameters to routes by enclosing them in {}
within the path. The parameters should be defined as function arguments, and AventusSharp will automatically infer their types.
using AventusSharp.WebSocket;using AventusSharp.WebSocket.Attributes;using Path = AventusSharp.WebSocket.Attributes.Path;
namespace Demo.Websocket.Routes{ [Prefix("Main")] public class MainRouter : WsRouter { // /main/ public string Index() { return "It's working"; }
// /main/demo/{id}, where {id} is inferred as an integer [Path("/Demo/{id}")] public string Test(int id) { return "It's a test for " + id; } }}
Calling Functions
You can also call functions within routes. This approach is useful when creating abstract classes for generic routers. Function calls in routes are executed at route initialization, so only predefined elements should be included. This functionality is demonstrated in the StorableWsRouter
class, which will be discussed later.
using AventusSharp.Routes;using Path = AventusSharp.Routes.Attributes.Path;
namespace Demo.Data.Routes{ public class MainRouter : Router { // / public string Index() { return "It's working"; }
// /mainrouter/{id}, where router name is generated by GetRouterName() [Path("/[GetRouterName]/{id}")] public string Test(int id) { return "It's a test for " + id; }
protected string GetRouterName() { return GetType().Name; } }}
With these tools, you can efficiently customize URLs, handle parameters, and add dynamic functionality within your routes.
Service Injection
AventusSharp supports injecting services that can be directly used within routes. In the example below, we’ll create a simple service to provide the current date and time.
public interface IDateTime{ DateTime Now { get; }}
public class SystemDateTime : IDateTime{ public DateTime Now => DateTime.Now;}
To register a service for injection, use the static Inject
function during application initialization.
private static void InitWs(VoidWithError initResult, WebApplication app){ WebSocketMiddleware.Configure((config) => {}); initResult.Run(WebSocketMiddleware.Register); app.Use(WebSocketMiddleware.OnRequest);
// Inject IDateTime service implementation WebSocketMiddleware.Inject<IDateTime, SystemDateTime>();}
Once injected, you can use IDateTime
in any route by including it as a parameter.
using AventusSharp.WebSocket;using Demo.Logic;
namespace Demo.Websocket.Routes{ public class MainRouter : WsRouter { public string Time(IDateTime dateTime) { return "It's " + dateTime.Now; } }}
Request Body
Any additional parameters in a route method signature will be treated as part of the request body. You can create route with a body
using AventusSharp.WebSocket;
namespace Demo.Websocket.Routes{ public class MainRouter : WsRouter { public string Hello(string name) { return "Hello " + name; } }}
Now, you can send a request with a JSON body containing a name
field, and it will be automatically injected into the Hello
method.
Voici une version reformulée en anglais au format Markdown, prête à être intégrée dans votre documentation :
Excluding a Method from Routing
If you have a public method in your router that you do not want to expose as a route, you can use the [NoRoute]
attribute. This prevents the method from being registered as a WebSocket route.
using AventusSharp.WebSocket;using AventusSharp.Tools.Attributes;
namespace Demo.Websocket.Routes{ public class MainRouter : WsRouter { public string Index() { return "It's working"; }
// The route /test won't exist [NoRoute] public string Test() { return "It's a test"; } }}
In this example, the /test
route won’t be created, even though the Test
method is public.
Managing Endpoints
By default, a router listens to the main WebSocket endpoint. If your router needs to listen to a different endpoint, you can specify it using the [EndPoint<T>]
attribute, where T
is the endpoint class.
using AventusSharp.WebSocket;using AventusSharp.WebSocket.Attributes;
namespace Demo.Websocket.Routes{ [EndPoint<MainEndPoint>] public class MainRouter : WsRouter { public string Index() { return "It's working"; }
public string Test() { return "It's a test"; } }}
In this case, the MainRouter
is explicitly associated with the MainEndPoint
class. All routes defined in MainRouter
will only be available through connections to this specific endpoint.
These features provide finer control over routing and endpoint management, ensuring that your WebSocket implementation in AventusSharp is both flexible and secure.
Voici la version reformulée en anglais et formatée en Markdown pour votre documentation :
Preconfigured Routes
AventusSharp includes a preconfigured router called StorableWsRouter<T>
. This generic router simplifies the creation of WebSocket routes for your storable objects. The type parameter T
represents the object type you want to manage, and the name of T
is used in place of [StorableName]
in the route paths.
By default, the following routes are automatically created:
Function | Channel | Response Type |
---|---|---|
GetAll | /[StorableName] | Single connection |
Create | /[StorableName]/Create | Broadcast |
CreateMany | /[StorableName]/CreateMany | Broadcast |
GetById | /[StorableName]/{id} | Single connection |
GetByIds | /[StorableName]/GetByIds | Single connection |
Update | /[StorableName]/{id}/Update | Broadcast |
UpdateMany | /[StorableName]/UpdateMany | Broadcast |
Delete | /[StorableName]/{id}/Delete | Broadcast |
DeleteMany | /[StorableName]/DeleteMany | Broadcast |
Key Benefits
- Ease of Use: Eliminates the need to manually define common routes for CRUD operations.
- Consistency: Ensures standardized routing structure across your WebSocket API.
- Flexibility: Supports both single-client responses and broadcast messages.
This feature is especially useful for quickly setting up WebSocket routes for storable objects in your application.
Example Usage
To create a router for a specific storable object, simply inherit from StorableWsRouter<T>
and provide your object type as the generic parameter. All the routes described above will be automatically available.
using AventusSharp.Data.Manager;using AventusSharp.WebSocket;using AventusSharp.Tools.Attributes;using Demo.Data;using Demo.Logic.DM;
namespace Demo.Websocket.Routes { public class UserRouter : StorableWsRouter<User> { protected override IGenericDM<User>? GetDM() { return UserDM.GetInstance(); }
// You can disable on specific route if you need [NoRoute] public override ResultWithError<User> Create(User item) { throw new NotImplementedException(); } }}