Skip to content

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.

MainRouter.cs
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:

  1. void: If the method returns void, an EmptyEvent is sent.
  2. WsEvent: If the method returns a WsEvent or a child, it is sent directly.
  3. Other Objects: Any other object is serialized into JSON and sent as a JsonEvent.
MainRouter.cs
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.

MainRouter.cs
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.cs
// MainRouter.cs
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
[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.

MainRouter.cs
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.

MainRouter.cs
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.

MainRouter.cs
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

MainRouter.cs
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.

MainRouter.cs
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.

MainRouter.cs
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:

FunctionChannelResponse Type
GetAll/[StorableName]Single connection
Create/[StorableName]/CreateBroadcast
CreateMany/[StorableName]/CreateManyBroadcast
GetById/[StorableName]/{id}Single connection
GetByIds/[StorableName]/GetByIdsSingle connection
Update/[StorableName]/{id}/UpdateBroadcast
UpdateMany/[StorableName]/UpdateManyBroadcast
Delete/[StorableName]/{id}/DeleteBroadcast
DeleteMany/[StorableName]/DeleteManyBroadcast

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.

UserRouter.cs
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();
}
}
}