如何在.NET Core MVC中调用Stack Exchange API并实现客户端自定义请求
对接Stack Exchange API实现标签数据获取方案
现有代码问题修正
- HttpClient配置错误:
site、client_id不需要放在请求头,Stack Exchange API的参数需放在URL查询参数中,无需配置默认redirect_uri请求头,同时需要开启自动解压缩处理API返回的gzip压缩内容 - 实体类不符合API返回结构:原有
Tags类的字段与Stack Exchange标签接口返回的字段不匹配,需调整映射关系 - 控制器继承错误:
TagsController不应继承Tags类,需继承ASP.NET MVC的Controller基类 - 依赖注入缺失:未注册
ITagsRepository与对应实现,运行时会触发服务解析异常
核心功能实现
1. 修正Startup配置与实体定义
using System.Net; using System.Net.Http.Headers; public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); services.AddHttpClient("stackoverflow", s => { s.BaseAddress = new Uri("https://api.stackexchange.com/2.3/"); s.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip")); s.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("deflate")); }).ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate }); // 注册仓储服务 services.AddScoped<ITagsRepository, TagsRepository>(); }
using System.Text.Json.Serialization; // 对应API返回的标签结构 public class StackTag { [JsonPropertyName("name")] public string Name { get; set; } // 使用次数即流行度 [JsonPropertyName("count")] public int Popularity { get; set; } // 使用率可基于总标签数自行计算 public decimal Usage { get; set; } } // API返回外层通用结构 public class StackApiResponse<T> { [JsonPropertyName("items")] public List<T> Items { get; set; } [JsonPropertyName("has_more")] public bool HasMore { get; set; } } public interface ITagsRepository { Task<List<StackTag>> GetTagsAsync(int take = 1000, string sort = "popular", string order = "desc"); }
2. 实现仓储层API请求逻辑
Stack Exchange API单页最多返回100条数据,拉取1000条需分10页请求:
public class TagsRepository : ITagsRepository { private readonly IHttpClientFactory _httpClientFactory; public TagsRepository(IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; } public async Task<List<StackTag>> GetTagsAsync(int take = 1000, string sort = "popular", string order = "desc") { var client = _httpClientFactory.CreateClient("stackoverflow"); var allTags = new List<StackTag>(); var page = 1; while (allTags.Count < take) { var pageSize = Math.Min(100, take - allTags.Count); var requestUrl = $"tags?page={page}&pagesize={pageSize}&order={order}&sort={sort}&site=stackoverflow"; var response = await client.GetFromJsonAsync<StackApiResponse<StackTag>>(requestUrl); if (response?.Items == null || !response.Items.Any()) break; allTags.AddRange(response.Items); if (!response.HasMore) break; page++; } // 计算使用率,可选逻辑 var total = allTags.Sum(t => t.Popularity); allTags.ForEach(t => t.Usage = Math.Round((decimal)t.Popularity / total * 100, 2)); return allTags.Take(take).ToList(); } }
3. 修正控制器逻辑
public class TagsController : Controller { private readonly ITagsRepository _tagsRepository; public TagsController(ITagsRepository tagsRepository) { _tagsRepository = tagsRepository; } public async Task<IActionResult> Index(int take = 1000, string sort = "popular", string order = "desc") { var tags = await _tagsRepository.GetTagsAsync(take, sort, order); ViewBag.Take = take; ViewBag.Sort = sort; ViewBag.Order = order; return View(tags); } }
4. 实现Index.cshtml视图
@model List<StackTag> <!-- 客户端自定义查询表单 --> <form method="get" asp-action="Index"> <div> <label>获取标签数量:</label> <input type="number" name="take" min="1" max="1000" value="@ViewBag.Take" required /> </div> <div> <label>排序规则:</label> <select name="sort"> <option value="popular" selected="@(ViewBag.Sort == "popular")">按流行度</option> <option value="name" selected="@(ViewBag.Sort == "name")">按名称</option> <option value="activity" selected="@(ViewBag.Sort == "activity")">按活跃度</option> </select> </div> <div> <label>排序方向:</label> <select name="order"> <option value="desc" selected="@(ViewBag.Order == "desc")">倒序</option> <option value="asc" selected="@(ViewBag.Order == "asc")">正序</option> </select> </div> <button type="submit">查询</button> </form> <!-- 标签数据展示 --> <table style="margin-top: 20px;border:1px solid #ccc;"> <thead> <tr> <th>标签名称</th> <th>流行度(使用次数)</th> <th>使用率(%)</th> </tr> </thead> <tbody> @foreach (var tag in Model) { <tr> <td>@tag.Name</td> <td>@tag.Popularity</td> <td>@tag.Usage</td> </tr> } </tbody> </table>
客户端自定义HTTP请求实现
客户端可通过视图中的表单提交自定义参数,控制器接收参数后动态拼接为Stack Exchange API的查询参数,即可实现自定义规则的API请求。如果需要前端直接发起请求,可将参数组装为fetch请求的查询字符串,通过后端做代理转发避免跨域问题。
内容的提问来源于stack exchange,提问作者SimonCrane
相关产品推荐
相关产品推荐

