手把手教你用C#对接爱发电API:Afdian.Sdk保姆级教程(含Webhook通知实战)

发布时间:2026/6/8 16:00:34

手把手教你用C#对接爱发电API:Afdian.Sdk保姆级教程(含Webhook通知实战) 手把手教你用C#对接爱发电APIAfdian.Sdk保姆级教程含Webhook通知实战在独立开发者和小团队的项目中赞助功能往往是维持项目可持续发展的重要途径。爱发电作为国内知名的创作者赞助平台为开发者提供了便捷的赞助接入方案。而Afdian.Sdk这个非官方.NET库则让C#开发者能够以更优雅的方式集成爱发电功能。本文将带你从零开始以一个开源工具项目为例完整实现从SDK集成到Webhook处理的全流程。1. 环境准备与基础配置在开始之前确保你的开发环境满足以下要求.NET 6.0或更高版本Visual Studio 2022或Rider最新版一个已注册的爱发电创作者账号首先通过NuGet安装Afdian.Sdkdotnet add package Afdian.Sdk接下来需要获取爱发电API的必要凭证登录爱发电开发者后台进入应用管理→API密钥记录下你的userId和token建议将这些敏感信息存储在安全的地方而不是硬编码在项目中。对于.NET项目可以使用secrets.json{ SecretsKeys: { AfdianToken: 你的token, AfdianUserId: 你的userId } }2. 核心API调用实战2.1 初始化客户端创建AfdianClient实例是使用SDK的第一步using Afdian.Sdk; var afdianClient new AfdianClient( userId: Configuration[SecretsKeys:AfdianUserId], token: Configuration[SecretsKeys:AfdianToken] );2.2 基础功能测试在正式开发前建议先进行连通性测试// 测试API连通性 string pingResult afdianClient.Ping(); Console.WriteLine($API连通性测试结果: {pingResult}); // 或者使用异步版本 var pingResultAsync await afdianClient.PingAsync();2.3 查询订单与赞助者获取赞助数据是核心需求SDK提供了多种查询方式// 查询第一页订单返回原始JSON字符串 string ordersJson afdianClient.QueryOrder(page: 1); // 查询赞助者返回强类型模型 var sponsors afdianClient.QuerySponsorModel(page: 1); // 异步查询示例 var recentOrders await afdianClient.QueryOrderModelAsync(page: 1, pageSize: 20);实际项目中你可能需要处理分页和错误情况try { int currentPage 1; bool hasMore true; var allOrders new ListOrder(); while (hasMore) { var pageResult await afdianClient.QueryOrderModelAsync(currentPage); allOrders.AddRange(pageResult.Data.List); hasMore pageResult.Data.TotalPage currentPage; currentPage; // 避免频繁调用 await Task.Delay(500); } Console.WriteLine($共获取到{allOrders.Count}条订单记录); } catch (Exception ex) { Console.WriteLine($查询订单时出错: {ex.Message}); }3. Webhook通知集成Webhook是实时获取赞助通知的最佳方式。下面我们实现一个完整的Webhook处理流程。3.1 配置Webhook端点首先在爱发电后台设置Webhook地址进入开发者后台→Webhook设置添加一个新的Webhook端点设置一个强密码用于验证签名3.2 实现Webhook控制器创建一个ASP.NET Core控制器处理Webhook通知[ApiController] [Route(api/webhook)] public class AfdianWebhookController : ControllerBase { private readonly IConfiguration _config; private readonly TelegramService _telegram; public AfdianWebhookController(IConfiguration config, TelegramService telegram) { _config config; _telegram telegram; } [HttpPost] public async TaskIActionResult HandleNotification([FromBody] AfdianWebhookPayload payload) { // 1. 验证签名 string secret _config[AfdianWebhookSecret]; if (!VerifySignature(payload, secret)) { return Unauthorized(); } // 2. 处理不同类型的事件 switch (payload.Data.Type) { case order.new: await HandleNewOrder(payload.Data.Order); break; case order.changed: await HandleOrderUpdate(payload.Data.Order); break; default: Console.WriteLine($未知事件类型: {payload.Data.Type}); break; } return Ok(new { ec 200, em success }); } private bool VerifySignature(AfdianWebhookPayload payload, string secret) { // 实现签名验证逻辑 } private async Task HandleNewOrder(Order order) { string message $ 新赞助: {order.Sponsor.Name} 赞助了 {order.Amount}元; await _telegram.SendMessageAsync(message); // 这里可以添加更多处理逻辑如更新数据库等 } }3.3 发送Telegram通知集成Telegram通知可以让开发者实时获知赞助情况public class TelegramService { private readonly HttpClient _httpClient; private readonly string _botToken; private readonly string _chatId; public TelegramService(IConfiguration config) { _botToken config[TelegramBotToken]; _chatId config[TelegramChatId]; _httpClient new HttpClient(); } public async Task SendMessageAsync(string text) { var url $https://api.telegram.org/bot{_botToken}/sendMessage; var content new FormUrlEncodedContent(new Dictionarystring, string { [chat_id] _chatId, [text] text, [parse_mode] Markdown }); await _httpClient.PostAsync(url, content); } }4. 进阶技巧与最佳实践4.1 错误处理与重试机制API调用可能会遇到各种网络问题实现健壮的错误处理很重要public async TaskT ExecuteWithRetryT(FuncTaskT action, int maxRetries 3) { int retryCount 0; while (true) { try { return await action(); } catch (HttpRequestException ex) when (retryCount maxRetries) { retryCount; var delay Math.Pow(2, retryCount) * 100; // 指数退避 await Task.Delay((int)delay); } } } // 使用示例 var sponsors await ExecuteWithRetry(() afdianClient.QuerySponsorModelAsync(1));4.2 性能优化建议当处理大量数据时考虑以下优化使用IAsyncEnumerable流式处理分页数据实现本地缓存减少API调用批量处理Webhook通知public async IAsyncEnumerableOrder GetAllOrdersAsync() { int page 1; while (true) { var result await afdianClient.QueryOrderModelAsync(page); foreach (var order in result.Data.List) { yield return order; } if (page result.Data.TotalPage) break; page; } } // 使用示例 await foreach (var order in GetAllOrdersAsync()) { // 处理每个订单 }4.3 安全注意事项在处理赞助数据时安全至关重要始终验证Webhook签名不要在前端暴露API密钥定期轮换凭证记录所有API调用和Webhook事件private bool VerifySignature(AfdianWebhookPayload payload, string secret) { var paramsToSign new Dictionarystring, string { [ts] payload.Ts.ToString(), [body] JsonSerializer.Serialize(payload.Data) }; var sortedParams paramsToSign.OrderBy(x x.Key); var stringToSign string.Join(, sortedParams.Select(x ${x.Key}{x.Value})) secret; using var sha256 SHA256.Create(); var computedHash sha256.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)); var computedSignature BitConverter.ToString(computedHash).Replace(-, ).ToLower(); return computedSignature payload.Signature; }5. 项目集成示例让我们以一个开源Markdown编辑器项目为例展示如何完整集成爱发电功能。5.1 添加赞助徽章在项目README中添加爱发电赞助徽章[![爱发电赞助](https://img.shields.io/badge/爱发电-支持作者-946CE6?logoafdianlogoColorwhite)](https://afdian.net/a/yourname)5.2 实现赞助者致谢页面创建一个ASP.NET Core页面展示赞助者public class SponsorsModel : PageModel { private readonly AfdianClient _afdian; public ListSponsor TopSponsors { get; set; } public SponsorsModel(AfdianClient afdian) { _afdian afdian; } public async Task OnGetAsync() { var result await _afdian.QuerySponsorModelAsync(page: 1, pageSize: 10); TopSponsors result.Data.List .OrderByDescending(s s.AllSumAmount) .Take(5) .ToList(); } }对应的Razor页面page model SponsorsModel h2特别感谢以下赞助者/h2 div classsponsor-grid foreach (var sponsor in Model.TopSponsors) { div classsponsor-card img srcsponsor.Avatar altsponsor.Name / h3sponsor.Name/h3 p累计赞助: sponsor.AllSumAmount 元/p psponsor.Message/p /div } /div5.3 自动化赞助者福利发放对于提供赞助者专属功能的项目可以实现自动化福利发放public class SponsorBenefitsService { private readonly AfdianClient _afdian; private readonly IUserRepository _userRepo; public SponsorBenefitsService(AfdianClient afdian, IUserRepository userRepo) { _afdian afdian; _userRepo userRepo; } public async Task UpdateBenefitsAsync() { var sponsors await GetAllActiveSponsorsAsync(); foreach (var user in await _userRepo.GetAllAsync()) { var isSponsor sponsors.Any(s s.UserId user.ExternalId); await _userRepo.UpdatePremiumStatusAsync(user.Id, isSponsor); } } private async TaskListSponsor GetAllActiveSponsorsAsync() { // 实现获取所有活跃赞助者的逻辑 } }

相关新闻