返回文章列表文章索引阅读全文
STARBLOG / 阅读手记
StarBlog博客开发笔记

StarBlog博客开发笔记(16):一些新功能

系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetCore开发博客项目 StarBlog - (3) 模型设计 基于.NetCore开发博客项目 StarBlog - (4) markdown博客批量导入 基于.NetCore开发博客项目 StarBl

曦远 (DealiAxy)约 19 分钟
目录9 个章节

系列文章

前言

最近好几天都忙着写代码,没更新文章,近期给博客增加了一些功能,本文一次性介绍~

新增的功能如下:

  • 系统监控:sentry、exceptionless、CLRStats
  • 访问统计
  • 配置管理
  • 初始化

系统监控

PS:其实前面两篇关于日志收集工具介绍的文章也是为了给本文做铺垫

系统监控这块包括日志收集、性能监测和系统状态监测。

日志收集和性能监测我交给了ExceptionLess和Sentry,这俩开源的工具可以很好的完成这些工作,详情可以看我之前写的这俩篇文章:

然后状态监测我是基于GitHub上的一个开源项目来魔改的:CLRStats

这个组件可以实时查看CPU、GC、线程的状态,不过原版的实现是作为一个中间件嵌入AspNetCore项目,并且访问的地址只能用Basic认证,不适用。

于是我把代码clone下来之后魔改了一下,变成一个可以调用的服务,并且重新写了API接口,终于方便起来了~

这个接口拿到的数据是这样的,后续在管理后台里面做成可视化图表也比较方便。

{
  "server": {
    "machineName": "machineName",
    "systemDateTime": "7/26/2022 11:30:22 PM"
  },
  "application": {
    "cpu": {
      "usagePercent": 0
    },
    "gc": {
      "gen0CollectCount": 24,
      "gen1CollectCount": 23,
      "gen2CollectCount": 22,
      "heapMemory": 38328872,
      "heapMemoryFormat": "36 M",
      "isServerGC": true
    },
    "thread": {
      "availableCompletionPortThreads": 1000,
      "availableWorkerThreads": 32766,
      "usedCompletionPortThreads": 0,
      "usedWorkerThreads": 1,
      "usedThreadCount": 29,
      "maxCompletionPortThreads": 1000,
      "maxWorkerThreads": 32767
    }
  }
}

具体代码就不复制粘贴了,我把它放在StarBlog.Contrib项目中,作为一个独立的组件方便调用。

访问统计

虽然前面这篇文章有介绍访问统计的实现:基于.NetCore开发博客项目 StarBlog - (11) 实现访问统计

不过只是单纯讲了通过中间件实现访问记录,这些数据存在数据库之后并没有被利用起来

现在就实现了一些简单的统计,目前主要实现了总览数据(总访问、今日、昨日访问)、趋势数据、指定日期统计,这几个功能。

逻辑代码在StarBlog.Web/Services/VisitRecordService.cs中

总览数据代码在这

PS:我发现FreeSQL的ISelect对象在链式操作时候的行为很奇怪,我知道是懒加载,但是已经执行了.Count()似乎还没执行,下一行调用的代码甚至会把前面的筛选条件加上,无奈我之内在方法内又写了一个嵌套的方法……

也就是这个GetQuerySet,这点让我这种用习惯DjangoORM的人觉得很不适应 = =..

这个接口计算总访问量、今日访问量、昨日访问量,方便做对比~~(受知乎的创作者中心启发)~~

public object Overview() {
  ISelect<VisitRecord> GetQuerySet() => _repo.Where(a => !a.RequestPath.StartsWith("/Api"));

  return new {
    TotalVisit = GetQuerySet().Count(),
    TodayVisit = GetQuerySet().Where(a => a.Time.Date == DateTime.Today).Count(),
    YesterdayVisit = GetQuerySet().Where(a => a.Time.Date == DateTime.Today.AddDays(-2).Date).Count(),
  };
}

趋势数据

也就是统计最近n天的访问量

PS:C#的日期处理还是比较舒服的

public object Trend(int days = 7) {
  return _repo.Where(a => !a.RequestPath.StartsWith("/Api"))
    .Where(a => a.Time.Date > DateTime.Today.AddDays(-days).Date)
    .GroupBy(a => a.Time.Date)
    .ToList(a => new {
      time = a.Key,
      date = $"{a.Key.Month}-{a.Key.Day}",
      count = a.Count()
    });
}

按日期统计

这个简单粗暴不用多说

public object Stats(DateTime date) {
  var data = _repo.Where(a => a.Time.Date == date.Date && !a.RequestPath.StartsWith("/Api"));
  return new { Count = data.Count() };
}

注意这里面所有的统计我都过滤了以/Api开头的地址,因为我只需要统计博客前台的访问量就行了。

配置管理

博客还是有很多需要配置的东西,比如说Host

之前我是写在appsettings.json文件里的,按理说也可以,修改这文件之后也能hot reload,不过问题是没法实现在管理后台中修改并保存

所以我打算实现一个配置管理的功能

一开始是把目光瞄准了KV数据库,甚至要求找一个嵌入式的、C#实现的开源项目,叠了这么多buff,果然没找到合适的

(不过前几天好像看到有个大佬发了篇文章介绍用C#手写一个KV数据库的,大赞!)

于是还是用博客本身的数据来实现好了,也不难

老规矩,继续写Service:StarBlog.Web/Services/ConfigService.cs

这里只把关键代码放出来,完整代码可以看GitHub

public class ConfigService {
    private readonly IConfiguration _conf;
    private readonly IBaseRepository<ConfigItem> _repo;

    public ConfigItem? GetByKey(string key) {
        var item = _repo.Where(a => a.Key == key).First();
        if (item == null) {
            // 尝试读取初始化配置
            var section = _conf.GetSection($"StarBlog:Initial:{key}");
            if (!section.Exists()) return null;
            item = new ConfigItem { Key = key, Value = section.Value, Description = "Initial" };
            item = AddOrUpdate(item);
        }

        return item;
    }

    public ConfigItem AddOrUpdate(ConfigItem item) {
        return _repo.InsertOrUpdate(item);
    }

    public int? Update(string key, string value, string? description = default) {
        var item = GetByKey(key);
        if (item == null) return null;

        item.Value = value;
        if (description != null) item.Description = description;
        return _repo.Update(item);
    }

    public string this[string key] {
        get {
            var item = GetByKey(key);
            return item == null ? "" : item.Value;
        }
        set {
            var item = GetByKey(key) ?? new ConfigItem { Key = key };
            item.Value = value;
            AddOrUpdate(item);
        }
    }
}

这个ConfigService实现了索引器,可以比较方便的实现配置的读取和保存

比如这样

var conf = xxx; // 注入 ConfigService
// 读取配置
Console.WriteLine(conf["host"]);
// 修改配置
conf["host"] = "http://dealiaxy.com";

同时我也写了几个接口,可以通过HTTP的方式管理配置,代码就不放了~

初始化

在我的设计中,这个功能是依赖于配置管理的

所以把配置管理做完之后,我的初始化页面也做出来了

看起来是这样的

1658850741512

也就是首次运行本项目的时候,会进入这个页面,目前的初始化配置就只有创建管理、设置Host两个,后续应该会慢慢增加其他的

后台是通过is_init这个字段来判断是否有初始化的

直接上Controller代码

[HttpGet]
public IActionResult Init([FromServices] ConfigService conf) {
    if (conf["is_init"] == "true") {
        _messages.Error("已经完成初始化!");
        return RedirectToAction(nameof(Index));
    }

    return View(new InitViewModel {
        Host = conf["host"]
    });
}

[HttpPost]
public IActionResult Init([FromServices] ConfigService conf, [FromServices] IBaseRepository<User> userRepo, InitViewModel vm) {
    if (!ModelState.IsValid) return View();

    // 保存配置
    conf["host"] = vm.Host;
    conf["is_init"] = "true";

    // 创建用户
    // todo 这里暂时存储明文密码,后期要换成MD5加密存储
    userRepo.Insert(new User {
        Id = Guid.NewGuid().ToString(),
        Name = vm.Username,
        Password = vm.Password
    });

    _messages.Success("初始化完成!");
    return RedirectToAction(nameof(Index));
}

同时还要实现一个View页面,这个就比较简单,代码不放了

_EOF_

StarBlog博客开发笔记(16):一些新功能

本文作者:
程序设计实验室
版权声明:
本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

相关文章

StarBlog博客开发笔记(18):实现本地Typora文章打包上传

前言 九月太忙,只更新了三篇文章,本来这个功能是从九月初就开始做的,结果一直拖到现在国庆假期才有时间完善并且写文章~ 之前我更新了几篇关于 Python 的文章,有朋友留言问是不是不更新 .Net 了,那肯定不能啊,我只能说**「我 全 都 要」**,所以我反手就更新了一篇Asp-Net-Core开发笔记。 然后顺便立个Flag:今年底前完成StarBlog系列文章的主体部分(即API开发+后台前

2022-10-06 · StarBlog博客开发笔记 · 约 1 分钟

StarBlog博客开发笔记(25):图片接口与文件上传

前言 上传文件的接口设计有两种风格,一种是整个项目只设置一个接口用来上传,然后其他需要用到文件的地方,都只存一个引用ID;另一种是每个需要文件的地方单独管理各自的文件。这俩各有优劣吧,本项目中选择的是后者的风格,文章图片和照片模块又要能CRUD又要批量导入,还是各自管理文件比较好。 图片接口 说会正题,先介绍一下图片相关接口。 图片列表 首先CRUD是肯定有的,图片列表的分页查看也是有的,不过因为

2023-02-05 · StarBlog博客开发笔记 · 约 1 分钟

StarBlog博客开发笔记(1):项目介绍

前言 OK,我也来造轮子了 博客系统从一开始用WordPress,再到后来用hexo、hugo之类的静态博客生成放github托管,一直在折腾 折腾是为了更好解决问题,最终还是打算自己花时间搞一个好了 本系列文章将记录博客的开发过程~ 后端基于最新的.Net6和Asp.Net Core框架,遵循RESTFul接口规范,前端基于Vue+ElementUI开发,可作为 .Net Core 入门项目学习

2022-04-05 · StarBlog博客开发笔记 · 约 1 分钟

讨论

共 0 条

良言一句三冬暖,恶语伤人六月寒。

加载评论中…