T2FGame.Action
1.0.0
See the version list below for details.
dotnet add package T2FGame.Action --version 1.0.0
NuGet\Install-Package T2FGame.Action -Version 1.0.0
<PackageReference Include="T2FGame.Action" Version="1.0.0" />
<PackageVersion Include="T2FGame.Action" Version="1.0.0" />
<PackageReference Include="T2FGame.Action" />
paket add T2FGame.Action --version 1.0.0
#r "nuget: T2FGame.Action, 1.0.0"
#:package T2FGame.Action@1.0.0
#addin nuget:?package=T2FGame.Action&version=1.0.0
#tool nuget:?package=T2FGame.Action&version=1.0.0
T2FGame.Action
T2FGame 框架的 Action 处理层,提供类似 ioGame BarSkeleton 的业务处理框架。
功能特性
- Action 注解:声明式路由配置
- Pipeline 处理链:可扩展的请求处理管道
- 参数绑定:自动解析请求参数和上下文
- 模块间调用:支持跨模块 Action 调用
- Result → ResponseMessage 转换:函数式错误处理集成
安装
<PackageReference Include="T2FGame.Action" />
核心概念
Action 控制器
类似于 ioGame 的 ActionController,使用注解声明路由:
[ActionController(cmd: CmdModule.User)]
public class UserController
{
private readonly IUserService _userService;
public UserController(IUserService userService)
{
_userService = userService;
}
/// <summary>
/// 用户登录
/// </summary>
[ActionMethod(subCmd: UserCmd.Login, Description = "用户登录")]
public async Task<LoginResponse> Login(LoginRequest request, FlowContext context)
{
var result = await _userService.LoginAsync(request.Username, request.Password);
// 设置认证状态
context.SetAuthenticated(result.UserId);
return new LoginResponse
{
UserId = result.UserId,
Token = result.Token
};
}
/// <summary>
/// 获取用户信息(需要认证)
/// </summary>
[ActionMethod(subCmd: UserCmd.GetInfo, RequireAuth = true)]
public async Task<UserInfo> GetUserInfo(FlowContext context)
{
var user = await _userService.GetByIdAsync(context.UserId);
return user.ToProto();
}
}
FlowContext(请求上下文)
public abstract class FlowContext
{
// 基本信息
public abstract string SessionId { get; }
public abstract long UserId { get; }
public abstract bool IsAuthenticated { get; }
public abstract int CmdMerge { get; }
public abstract int MessageId { get; }
// 原始请求数据
public abstract byte[]? RequestData { get; }
// 认证管理
public abstract bool SetAuthenticated(long userId);
// 响应发送
public abstract ValueTask SendAsync(IMessage response);
public abstract ValueTask SendRawAsync(byte[] data);
// 元数据
public abstract string? GetMetadata(string key);
public abstract void SetMetadata(string key, string value);
}
Pipeline 处理链
内置处理器
| 处理器 | 顺序 | 功能 |
|---|---|---|
| ValidationHandler | 100 | 参数验证 |
| AuthenticationHandler | 200 | 认证检查 |
| CacheHandler | 300 | 响应缓存 |
| ActionInvokerHandler | 500 | 执行 Action |
| ExceptionHandler | 900 | 异常处理 |
| LoggingHandler | 950 | 日志记录 |
| MetricsHandler | 980 | 指标统计 |
自定义处理器
public class RateLimitHandler : IActionHandler
{
public int Order => 150; // 在认证之前
public string Name => "RateLimit";
private readonly IRateLimiter _rateLimiter;
public RateLimitHandler(IRateLimiter rateLimiter)
{
_rateLimiter = rateLimiter;
}
public async ValueTask<bool> HandleAsync(ActionPipelineContext context)
{
var key = $"rate:{context.FlowContext.SessionId}:{context.ActionInfo.CmdMerge}";
if (!await _rateLimiter.TryAcquireAsync(key))
{
context.SetResponse(ResponseMessage.Failure(
context.ActionInfo.CmdMerge,
ErrorCodes.RateLimited,
"请求过于频繁"));
return false; // 中断管道
}
return true; // 继续执行
}
}
注册处理器
services.AddSingleton<IActionHandler, RateLimitHandler>();
模块间调用
[ActionController(cmd: CmdModule.Battle)]
public class BattleController
{
[ActionMethod(subCmd: BattleCmd.Start)]
public async Task<BattleStartResponse> StartBattle(
BattleStartRequest request,
FlowContext context)
{
// 调用用户模块获取玩家信息
var userInfo = await context.ModuleInvoker.InvokeAsync<UserInfo>(
CmdKit.Merge(CmdModule.User, UserCmd.GetInfo),
context.UserId);
// 创建战斗
var battle = await CreateBattle(userInfo, request);
return new BattleStartResponse { BattleId = battle.Id };
}
}
Result 模式集成
使用 ResultExtensions
[ActionMethod(subCmd: UserCmd.UpdateInfo)]
public async Task<ResponseMessage> UpdateUserInfo(
UpdateUserRequest request,
FlowContext context)
{
// 业务层返回 Result<T>
Result<UserInfo> result = await _userService.UpdateAsync(
context.UserId,
request.Nickname);
// 转换为 ResponseMessage
return result.ToResponseMessage(context.CmdMerge);
}
// 带转换函数
[ActionMethod(subCmd: UserCmd.GetProfile)]
public async Task<ResponseMessage> GetProfile(FlowContext context)
{
Result<User> result = await _userService.GetByIdAsync(context.UserId);
return result.ToResponseMessage(
context.CmdMerge,
user => user.ToProfileProto()); // 转换函数
}
Action 注册
自动扫描注册
// 扫描程序集注册所有 Action
services.AddActionMethodRegistry(options =>
{
options.ScanAssemblies(typeof(UserController).Assembly);
});
// 或指定多个程序集
services.AddActionMethodRegistry(options =>
{
options.ScanAssemblies(
typeof(UserController).Assembly,
typeof(BattleController).Assembly);
});
手动注册
var registry = new ActionMethodRegistry();
registry.RegisterController<UserController>();
registry.RegisterController<BattleController>();
异常处理
内置异常处理器
public class GameExceptionHandler : IExceptionHandler
{
public int Order => 0;
public bool CanHandle(Exception exception) => exception is GameException;
public ResponseMessage Handle(Exception exception, ActionPipelineContext context)
{
var gameEx = (GameException)exception;
return ResponseMessage.Failure(
context.ActionInfo.CmdMerge,
gameEx.ErrorCode,
gameEx.Message);
}
}
指标统计
// 获取 Action 统计信息
var metrics = serviceProvider.GetService<InMemoryActionMetrics>();
var stats = metrics.GetAllStats();
foreach (var (cmdMerge, stat) in stats)
{
Console.WriteLine($"Command: {CmdKit.CmdToString(cmdMerge)}");
Console.WriteLine($" Requests: {stat.RequestCount}");
Console.WriteLine($" Errors: {stat.ErrorCount}");
Console.WriteLine($" Avg Response Time: {stat.AverageResponseTimeMs:F2}ms");
Console.WriteLine($" Max Response Time: {stat.MaxResponseTimeMs}ms");
}
目录结构
T2FGame.Action/
├── Attributes/
│ ├── ActionControllerAttribute.cs # 控制器注解
│ └── ActionMethodAttribute.cs # 方法注解
├── Context/
│ ├── FlowContext.cs # 请求上下文基类
│ └── ResponseMessage.cs # 响应消息
├── Extensions/
│ └── ResultExtensions.cs # Result 转换扩展
├── Invoker/
│ ├── IModuleInvoker.cs # 模块调用接口
│ └── ModuleInvoker.cs # 模块调用实现
├── Pipeline/
│ ├── ActionPipeline.cs # 处理管道
│ ├── ActionPipelineContext.cs # 管道上下文
│ ├── IActionHandler.cs # 处理器接口
│ ├── IExceptionHandler.cs # 异常处理器接口
│ ├── ErrorCodes.cs # 错误码定义
│ └── Handlers/
│ ├── ValidationHandler.cs
│ ├── AuthenticationHandler.cs
│ ├── ActionInvokerHandler.cs
│ ├── ExceptionHandler.cs
│ ├── LoggingHandler.cs
│ └── MetricsHandler.cs
└── Registry/
├── ActionMethodRegistry.cs # Action 注册表
└── ActionMethodInfo.cs # Action 元信息
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net9.0
- Google.Protobuf (>= 3.28.3)
- Microsoft.Extensions.Caching.Memory (>= 9.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.0)
- T2FGame.Core (>= 1.0.0)
- T2FGame.Protocol (>= 1.0.0)
NuGet packages (5)
Showing the top 5 NuGet packages that depend on T2FGame.Action:
| Package | Downloads |
|---|---|
|
T2FGame
T2FGame Framework - A high-performance distributed game server framework inspired by ioGame. This meta-package includes all T2FGame components. |
|
|
T2FGame.Network.Socket
T2FGame Framework - High-performance Socket server based on SuperSocket (TCP/UDP/WebSocket) |
|
|
T2FGame.Cluster.Orleans
A high-performance game server framework |
|
|
T2FGame.Room
T2FGame Framework - Game room framework for multiplayer games, inspired by ioGame's RoomKit |
|
|
T2FGame.Cache.Redis
T2FGame Framework - Redis distributed cache implementation for high-performance caching |
GitHub repositories
This package is not used by any popular GitHub repositories.