使用.Net分析.Net达人挑战赛参与情况

2022-11-18 10:06:36 浏览数 (1)

背景

C#是我2012年在大学课程中接触的,.NET Framework 我也一直使用至今。从2014年.NET 开源,2019年发布.NET Core 3 的时候,公司刚好有 Nvidia Jetson 平台 Linux 嵌入式设备的开发任务,.NET 又刚是适用于 Windows, Linux, 和 macOS 的跨平台解决方案。对于我个人来说也容易上手,就又开始了对其新的认识历程,按照微软的官方.NET 文档也做了几个练手的项目。

21年底的时候帮大学的老师开发了一个园林的信用评价系统,这个任务可以说是相当紧急了,前后端全部一个人完成,还只有元旦休息的这三四天的时间,虽然任务艰巨,算是个挑战,刚好那个时候在学完了.NET的《创建自己的第一个Web应用》,那就让挑战更猛烈些吧 —— 用.NET。其实也不是为了调整,学习一门语言更好的方式是跟着项目边学边写,硬着头皮爆肝午夜十二点,还好是按时完成了交付。

那个时候自己写的认证和授权的中间件还把Jwt认证实现了一遍。好吧,这就是没有老师带的后果吧。然后当我撸完项目闲下来,就在朋友圈看到杨中科老师发的.NET录播分享。真,真是及时雨啊。

再然后收到杨老师的朋友圈邀请,我真的不是觊觎奖品里有杨老师还没发的.NET的新书。

就这样我参加了 《.NET 20周年学习挑战赛|寻找 .NET 技术达人》 ,并完成了三个模块的挑战。通过这三个挑战,系统性的对.NET的能力有了更全的了解。发现.NET 可以搞更多有意思的事情,通过Xamarin技术的初步认识,我玩起了在桌边因为疫情居家落灰的小米手表,最近在研究用Xamarin技术怎么通过蓝牙模拟HID设备控制电脑,做个腕间飞鼠。

回到挑战赛,挑战赛在5月21日结束,我就想问问举办方关于杨老师的书,啊,不,是奖品,您看我有机会嘛?

自己动手丰衣足食,自己抓取分析下排行榜不就完了嘛。

所需知识

基于我已经完成的代码,我整理了一下,完成这个小项目(一切皆项目)所需要的知识点。

首先我们需要获取到排行榜的数据,就可能需要用到爬虫技术,进行网页的抓取和分析,之后在分析网页请求的时候,我发现官方的排行榜数据是通过API获取到的,并且不需要鉴权,这可就太方便啦。我们稍微改一下参数就可以一次性拉取到排行数据了。

代码语言:javascript复制
https://docs.microsoft.com/api/challenges/17c618cc-3c82-4a29-b2c6-d78b1de10b98/leaderboard?$top=100&$skip=0

F12打开网页调试,拿到对应挑战赛排行页面的如上API地址,将参数top改为100,skip改为0即可。

这样我们需要的其它技术或知识点如下:

•通过 HttpClient 使用 REST 服务•异步编程 async await 基本使用•使用 System.Text.Json 分析 Json 数据•LINQ 的基本方法

当然还有一些其它非必要,如匿名对象等。

实现思路

准备数据

先将拿到的三个挑战赛排名数据创建一个匿名的对象

代码语言:javascript复制
// API 里有课程名,直接写出了为了好认
var apiInfo = new[]{
    (
        title:"C# 学习",
        url:"https://docs.microsoft.com/api/challenges/17c618cc-3c82-4a29-b2c6-d78b1de10b98/leaderboard?$top=100&$skip=0"
    ),
    (
        title:"ASP.NET Core 开发",
        url:"https://docs.microsoft.com/api/challenges/b64cc891-e999-4652-909b-d545698a2e60/leaderboard?$top=100&$skip=0"
    ),
    (
        title:".NET 移动应用",
        url:"https://docs.microsoft.com/api/challenges/38ec3c07-3ce6-4fb8-b423-b79166202364/leaderboard?$top=100&$skip=0"
    )
};

设计存储数据的对象

创建一个存储挑战者学习信息的类,里面含有挑战者名称 userName ,完成挑战的数量 learnNum 和所完成的挑战 learnName ,以及一个添加新的完成挑战类目的方法 addClass

代码语言:javascript复制
public class StudyInfo {
    public StudyInfo(string userName, int learnNum, List<string> learnName)
    {
        this.userName = userName;
        this.learnNum = learnNum;
        this.learnName = learnName;
    }
    public string userName { get;private set; }
    public int learnNum { get; private set; }
    public List<string> learnName{ get; private set; }
    public void addClass(string className) {
        this.learnNum  ;
        this.learnName.Add(className);
    }
}

排行榜数据获取

使用 HttpClient 获取挑战排行榜的数据

代码语言:javascript复制
var client = new HttpClient();
foreach (var item in apiInfo)
{
    string jsoninfo = await client.GetStringAsync(item.url);
    // 分析
}

数据解析和输出

进行 json 数据的解析,通过具体返回的内容我们可以很容易的发现字段所代表的含义。

totalScoreUnits 表示本次挑战的小节数,只有完成这么多小节的学习才算完成了挑战,使用 var user = new List<StudyInfo>(); 来存储用户的挑战信息,根据解析的结果进行新建或者更新数据。最后将结果进行逆序排列输出到文件。

System.Text.Json 的使用上我们需要注意几点:

•获取的 json 的值时,我们需要进行强制数据转换,保存用户学习课程的 score 需要用 float 类型•遍历 json 数组时,需要先将其 JsonNode 对象进行 AsArray() 处理,JsonNode 是不支持 foreach 的•最后输出 json 序列化时,需要进行 options 的设置,这样才不会将中文字符进行编码

代码语言:javascript复制
var options = new JsonSerializerOptions { Encoder = JavaScriptEncoder.Create(UnicodeRanges.All) };
代码语言:javascript复制

JsonNode jsonNode = JsonNode.Parse(jsoninfo)!;
// 合集总课程数
int classnum = (int)jsonNode["totalScoreUnits"]!;
foreach (var uinfo in jsonNode["results"]!.AsArray())
{
    // 学完的用户
    if ((float)uinfo["score"]! == classnum)
    {
        // 看看有没有这个用户的信息
        var temp = user.FirstOrDefault(e => e.userName == (string)uinfo["userDisplayName"]!);
        if (temp is null)
        {
            // 初始创建这个用户
            user.Add(new StudyInfo((string)uinfo["userDisplayName"]!, 1, new List<string>() { item.title }));
        }
        else
        {
            // 有,更新学习数据
            temp.addClass(item.title);
        }
    }
}
// 逆序排序后转为json字符存入文件
var jsonRes = JsonSerializer.Serialize(user.OrderByDescending(x => x.learnNum), options);
File.WriteAllText("output.json", jsonRes);

进行简单的分析

这里主要使用了 Linq 操作,如果对 Linq 不了解,可以去看一下杨老师的相关课程。

代码语言:javascript复制
// 简单分析一下
Console.WriteLine($"完成《C# 学习》{user.Where(x=>x.learnName.IndexOf("C# 学习")>-1).Count()}人");
Console.WriteLine($"完成《ASP.NET Core 开发》{user.Where(x => x.learnName.IndexOf("ASP.NET Core 开发") > -1).Count()}人");
Console.WriteLine($"完成《.NET 移动应用》{user.Where(x => x.learnName.IndexOf(".NET 移动应用") > -1).Count()}人");
Console.WriteLine($"仅完成 1 次挑战 {user.Where(x => x.learnNum == 1).Count()}人");
Console.WriteLine($"仅完成 2 次挑战 {user.Where(x => x.learnNum ==2).Count()}人");
Console.WriteLine($"共完成 3 次挑战 {user.Where(x => x.learnNum == 3).Count()}人n 分别是");

foreach (var item in user.Where(x => x.learnNum == 3)) {
    Console.WriteLine(item.userName);
}

最后

详细的代码实现我放在 .Net 达人挑战赛参与分析 github[1] ,感兴趣的同学可以自取。

.NET 是一个免费的跨平台开源开发人员平台,希望 .NET 可以发展的越来越好。如果你希望可以更深入的了解一下 .NET ,强烈推荐去B站关注杨中科老师[2]去学习他的相关视频课程。你也可以关注“dotNet跨平台”公众号了解更多的.NET技术;.NET 学习和社区活动 可以关注:MSReactor 。

References

[1] .Net 达人挑战赛参与分析 github: https://github.com/marin1993/.NetChallengesInfo.git [2] B站关注杨中科老师: https://space.bilibili.com/27948784

0 人点赞