用C#对接爱发电API:从零构建赞助系统全指南

在独立开发者的生态中,爱发电平台为创作者提供了稳定的赞助收入渠道。本文将深入探讨如何通过C#实现与爱发电API的无缝对接,从基础配置到高级数据处理,打造一个完整的赞助管理系统。

1. 环境准备与基础配置

在开始对接前,需要确保开发环境就绪。推荐使用Visual Studio 2022或更高版本,并安装.NET 6+运行时。创建一个新的控制台应用或Web API项目作为起点。

首先通过NuGet安装Afdian.Sdk包:

dotnet add package Afdian.Sdk

获取开发者凭证是第一步。登录爱发电开发者后台,在"应用管理"中创建新应用,记录下 userId token 这两个关键参数。建议将这些敏感信息存储在安全的地方:

// 推荐使用.NET的Secret Manager存储凭证
// 在项目目录执行:dotnet user-secrets init
// 然后设置密钥:
dotnet user-secrets set "Afdian:UserId" "your_user_id"
dotnet user-secrets set "Afdian:Token" "your_token"

2. 初始化客户端与基础测试

创建AfdianClient实例是核心操作。建议采用依赖注入方式,便于在整个应用中共享客户端:

using Afdian.Sdk;

// 从配置或密钥管理器获取凭证
var userId = config["Afdian:UserId"];
var token = config["Afdian:Token"];

// 创建客户端实例
var afdianClient = new AfdianClient(userId, token);

进行Ping测试验证连接性:

try {
    var pingResult = afdianClient.Ping();
    Console.WriteLine($"API连接测试成功: {pingResult}");
} catch (Exception ex) {
    Console.WriteLine($"连接测试失败: {ex.Message}");
}

3. 订单数据查询与处理

爱发电API提供了两种订单查询方式:原始JSON和强类型模型。对于长期维护的项目,推荐使用强类型方式:

// 查询第一页订单
var orderPage = await afdianClient.QueryOrderModelAsync(page: 1);

// 处理订单数据
if (orderPage?.Data?.List != null) {
    foreach (var order in orderPage.Data.List) {
        Console.WriteLine($"订单ID: {order.OutTradeNo}");
        Console.WriteLine($"赞助金额: {order.TotalAmount}");
        Console.WriteLine($"赞助时间: {order.CreateTime}");
    }
}

订单分页是常见需求,下面是一个完整的分页查询示例:

public async Task<List<Order>> GetAllOrdersAsync() {
    var allOrders = new List<Order>();
    int currentPage = 1;
    bool hasMore = true;
    
    while (hasMore) {
        var page = await afdianClient.QueryOrderModelAsync(currentPage);
        if (page?.Data?.List != null) {
            allOrders.AddRange(page.Data.List);
            hasMore = page.Data.TotalPage > currentPage;
            currentPage++;
        } else {
            hasMore = false;
        }
        
        // 避免频繁请求
        await Task.Delay(500);
    }
    
    return allOrders;
}

4. 赞助者管理与高级功能

赞助者数据是核心业务信息。以下代码展示了如何处理赞助者信息并构建本地数据库:

public class SponsorService {
    private readonly AfdianClient _client;
    private readonly AppDbContext _db;
    
    public SponsorService(AfdianClient client, AppDbContext db) {
        _client = client;
        _db = db;
    }
    
    public async Task SyncSponsorsAsync() {
        var sponsors = await GetAllSponsorsAsync();
        
        foreach (var sponsor in sponsors) {
            var existing = await _db.Sponsors
                .FirstOrDefaultAsync(s => s.UserId == sponsor.UserId);
                
            if (existing == null) {
                _db.Sponsors.Add(new Sponsor {
                    UserId = sponsor.UserId,
                    Name = sponsor.Name,
                    Avatar = sponsor.Avatar,
                    LastSponsorTime = sponsor.LastSponsorTime,
                    TotalAmount = sponsor.TotalAmount
                });
            } else {
                existing.LastSponsorTime = sponsor.LastSponsorTime;
                existing.TotalAmount = sponsor.TotalAmount;
            }
        }
        
        await _db.SaveChangesAsync();
    }
    
    private async Task<List<Sponsor>> GetAllSponsorsAsync() {
        // 类似GetAllOrdersAsync的实现
    }
}

对于Web应用,可以设置定时任务定期同步数据:

// 在Program.cs中配置定时任务
builder.Services.AddHostedService<SponsorSyncService>();

// SponsorSyncService实现
public class SponsorSyncService : BackgroundService {
    protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
        while (!stoppingToken.IsCancellationRequested) {
            try {
                var service = Services.GetRequiredService<SponsorService>();
                await service.SyncSponsorsAsync();
            } catch (Exception ex) {
                Logger.LogError(ex, "同步赞助者数据失败");
            }
            
            await Task.Delay(TimeSpan.FromHours(1), stoppingToken);
        }
    }
}

5. 异常处理与性能优化

API调用可能遇到各种异常情况,需要健壮的错误处理机制:

public async Task<OrderPage> SafeQueryOrdersAsync(int page) {
    try {
        return await _client.QueryOrderModelAsync(page);
    } catch (HttpRequestException ex) {
        if (ex.StatusCode == System.Net.HttpStatusCode.TooManyRequests) {
            // 处理速率限制
            await Task.Delay(5000);
            return await SafeQueryOrdersAsync(page);
        }
        throw;
    } catch (Exception) {
        // 记录日志并重试
        await Task.Delay(1000);
        return await SafeQueryOrdersAsync(page);
    }
}

对于高频访问场景,可以引入缓存机制:

public class CachedAfdianService {
    private readonly AfdianClient _client;
    private readonly IMemoryCache _cache;
    
    public async Task<SponsorPage> GetSponsorsAsync(int page) {
        var cacheKey = $"sponsors_page_{page}";
        
        return await _cache.GetOrCreateAsync(cacheKey, async entry => {
            entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5);
            return await _client.QuerySponsorModelAsync(page);
        });
    }
}

6. 实际应用场景扩展

将爱发电数据整合到用户系统可以实现个性化功能。以下示例展示了如何为赞助者提供专属内容:

public class PremiumContentController : ControllerBase {
    [HttpGet("exclusive")]
    public IActionResult GetExclusiveContent() {
        var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
        
        var isSponsor = _db.Sponsors
            .Any(s => s.UserId == userId && s.LastSponsorTime > DateTime.Now.AddMonths(-1));
            
        if (!isSponsor) {
            return Unauthorized("需要成为近期赞助者才能访问此内容");
        }
        
        return Ok(new {
            Content = "这里是赞助者专属内容...",
            VideoUrl = "https://example.com/exclusive-video"
        });
    }
}

对于桌面应用,可以实现赞助者徽章系统:

public class UserBadgeService {
    public string GetBadgeLevel(string userId) {
        var sponsor = _db.Sponsors.FirstOrDefault(s => s.UserId == userId);
        
        if (sponsor == null) return "普通用户";
        
        return sponsor.TotalAmount switch {
            >= 500 => "钻石赞助者",
            >= 200 => "黄金赞助者",
            >= 100 => "白银赞助者",
            _ => "赞助者"
        };
    }
}

7. 监控与数据分析

建立数据监控面板可以帮助了解赞助情况:

public class SponsorDashboard {
    public async Task<DashboardModel> GetDashboardDataAsync() {
        var orders = await _orderService.GetRecentOrdersAsync(30);
        var sponsors = await _sponsorService.GetActiveSponsorsAsync();
        
        return new DashboardModel {
            TotalAmount = orders.Sum(o => o.TotalAmount),
            NewSponsors = sponsors.Count(s => s.FirstSponsorDate > DateTime.Now.AddDays(-30)),
            TopSponsors = sponsors
                .OrderByDescending(s => s.TotalAmount)
                .Take(5)
                .ToList(),
            RecentOrders = orders
                .OrderByDescending(o => o.CreateTime)
                .Take(10)
                .ToList()
        };
    }
}

对于长期项目,可以考虑将数据导出进行分析:

public async Task<IActionResult> ExportSponsorData() {
    var sponsors = await _db.Sponsors.ToListAsync();
    
    var csv = new StringBuilder();
    csv.AppendLine("用户ID,昵称,头像链接,最后赞助时间,总金额");
    
    foreach (var s in sponsors) {
        csv.AppendLine($"\"{s.UserId}\",\"{s.Name}\",\"{s.Avatar}\",\"{s.LastSponsorTime}\",{s.TotalAmount}");
    }
    
    return File(Encoding.UTF8.GetBytes(csv.ToString()), "text/csv", "sponsors.csv");
}

更多推荐