开发专栏
使用 Razor Pages 打造查看真实 IP、IPv6 检测网站 —— 树莓派彩蛋篇
3 年前
3745
服务器端开发 ASP.NET 树莓派 Razor Pages

本文是Razor Pages打造IP检测网站的最后一篇——树莓派彩蛋篇。今天将会使用视图组件模块化代码,以及通过C#获取树莓派的型号,一起动手吧。

使用 Razor Pages 打造查看真实 IP、IPv6 检测网站系列文章:

本篇文章对应的代码可以在 https://github.com/huhubun/BunIp/tree/simple_ver​ 查看到。

完整实现可以访问 https://ip.bun.plus/ 体验。

背景

我主要使用的主机是腾讯云,可惜腾讯云目前没有提供免费的 IPv6 给虚拟机(呐,有点过分唉,阿里云和 Vultr 明明都有的),所以把闲置的树莓派利用起来!

IPv6 一大亮点就是不再需要折腾内网穿透,如果获得的是公网 IPv6,即便把树莓派放在家里,其他拥有公网 IPv6 的人也可以直接访问到的~美滋滋。

使用 C# 获取树莓派型号

通过搜索,我了解到访问 /proc/device-tree/model 即可获得树莓派的型号:

$ cat /proc/device-tree/model
Raspberry Pi 3 Model B Rev 1.2

因为这是个文本文件,所以只需要用 File 去读取即可。在 Helpers 文件夹中新建 PiHelper.cs

using System.IO;

namespace IpTest.Helpers
{
    public static class PiHelper
    {
        const string MODEL_PATH = "/proc/device-tree/model";
        const string MODEL_PREFIX = "Raspberry Pi";

        /// <summary>
        /// 获取树莓派版本号
        /// </summary>
        /// <returns></returns>
        public static string GetModel()
        {
            if (File.Exists(MODEL_PATH))
            {
                var model = File.ReadAllText(MODEL_PATH).TrimEnd((char)0);

                if (model.StartsWith(MODEL_PREFIX))
                {
                    return model;
                }
            }

            return null;
        }
    }
}

这个方法首先判断了 /proc/device-tree/model 是否存在,如果存在的话就读取其中所有文本(我的树莓派读取的内容最后有一个 ASCII 为 0 的字符,需要将其去除,否则网页上会显示成乱码),如果 model 的内容以 Raspberry Pi 开头则说明是树莓派,返回型号,否则返回 null

接着我们来到 /Pages/Shared/_Layout.cshtml 文件,在 <footer> 部分显示出树莓派型号,修改后的 <footer> 如下:

<footer class="border-top footer text-muted">
    <div class="container">
        &copy; 2020 - IpTest - <a asp-area="" asp-page="/Privacy">Privacy</a>

        @{
            var piModel = IpTest.Helpers.PiHelper.GetModel();
        }

        @if (piModel != null)
        {
            <span class="float-right">Powered by @piModel</span>
        }
    </div>
</footer>

通过 View Component(视图组件)模块化代码

在上一步中,我们在 _Layout.cshtml 里添加了获取树莓派型号的代码,但实际上通过什么方法获取模型、什么时候应该显示模型,其实不属于 _Layout.cshtml 的工作,现在的做法导致 _Layout.cshtml 和获取型号的逻辑耦合在了一起。

使用过 vue 等框架的朋友一定体验过自定义组件的方便性。在 ASP.NET Core 中提供了 View Component(视图组件),它可以配合 Tag Helpers,就可以实现将获取型号的代码单独放在一个名为 PiModel 的组件中,然后在 _Layout.cshtml 中添加一个类似 HTML 标签的东西 <pi-model />,从而让逻辑互相独立。

除了让各个部分的逻辑保持独立互不干扰外,对于可重用的内容也非常适合使用组件来实现,这里只是抛砖引玉将显示树莓派模型这么一个小功能做成组件。

创建 View Component

/Pages/Shared 文件夹下新增一个名为 Components 的文件夹,默认情况下 Razor Pages 会从这里加载组件。接着在 Components 文件夹里新建一个名为 PiModel 的文件夹,用于实现我们的树莓派型号组件。

视图组件包含三个部分:

  • 显示部分,用于输出页面呈现的内容。右键单击 PiModel 文件夹,依次选择 添加 - 新建项 - ASP.NET Core - Razor 视图 - 空,命名为 Default.cshtml注意是 Razor 视图,而不是 Razor 页面!
  • 逻辑部分,用于实现相关业务逻辑。在 PiModel 文件夹中添加一个名为 PiModelViewComponent 的类。这个类的名字会和 Tag Helpers 有关联,当类名 ViewComponent 之前的部分将成为 Tag Helper 的名称。当我们想要 <pi-model> 这样的标签就需要按大小写(首字母和每个连字符后的字母需要大写)创建类的名称:PiModel,所以连在一起就是 PiModelViewComponent
  • 模型部分,用于在业务逻辑部分和显示部分中传递数据。在 PiModel 文件夹中添加一个名为 ViewModel 的类即可。

有点像一个缩小版的 MVC…完整的效果如下:

PiModelViewComponent

实现 View Component 中的业务代码

首先我们实现 ViewModel,因为它是业务和显示之间的纽带。这里只有一个存储了树莓派型号的字符串需要传递,那么就在 ViewModel 中新建一个字符串类型的属性即可:

namespace IpTest.Pages.Shared.Components.PiModel
{
    public class ViewModel
    {
        public string PiModel { get; set; }
    }
}

接着实现 PiModelViewComponent,它必须派生自 ViewComponent 类才会被识别为视图组件;然后为它添加一个 Invoke() 方法,并在其中填充 ViewModel 并通过 View() 返回:

using IpTest.Helpers;
using Microsoft.AspNetCore.Mvc;

namespace IpTest.Pages.Shared.Components.PiModel
{
    public class PiModelViewComponent : ViewComponent
    {
        public IViewComponentResult Invoke()
        {
            return View(new ViewModel
            {
                PiModel = PiHelper.GetModel()
            });
        }
    }
}

当使用视图组件时,会触发 Invoke() 方法。这个方法还有一个异步版本 InvokeAsync(),可以通过视图组件方法了解。

然后把显示部分实现,修改 Default.cshtml

@model IpTest.Pages.Shared.Components.PiModel.ViewModel

@if (Model.PiModel != null)
{
    <span class="float-right">Powered by @Model.PiModel</span>
}

我们还得在 _ViewImports.cshtml 文件中把刚刚创建的视图组件导入为 Tag Helper,在文件末尾增加:

@addTagHelper *, IpTest

代码最后的 IpTest 是我们的程序集名称,这样能够导入整个程序集里所有的 Tag Helper。

最后来到 _Layout.cshtml 文件,把之前在 <footer> 里增加的代码删除,改为我们的组件。最终 <footer> 部分如下:

<footer class="border-top footer text-muted">
    <div class="container">
        &copy; 2020 - IpTest - <a asp-area="" asp-page="/Privacy">Privacy</a>

        <vc:pi-model />
    </div>
</footer>

视图组件的 Tag Helper 以 vc: 开头,然后我们的组件类为 PiModelViewComponent,还记得上面说的命名约定吧,PiModel 会转换为 pi-model,所以标签写成 <vc:pi-model>

最终页面的访问效果:

访问树莓派效果

为树莓派安装 .NET 5

树莓派需要使用手动安装的方式,目前不能通过包管理器安装。我使用的是树莓派3代,安装了 Raspberry Pi OS (32-bit),所以我需要使用 32 位的 .NET 5 Runtime。

访问 https://dotnet.microsoft.com/download/dotnet/5.0 下载最新的 .NET 5 Arm32 Runtime 到树莓派上,然后参考 在 Debian 上手动安装 的方案:

sudo mkdir -p "$HOME/dotnet" && tar zxf aspnetcore-runtime-5.0.0-linux-arm.tar.gz -C "$HOME/dotnet"
export DOTNET_ROOT=$HOME/dotnet
export PATH=$PATH:$HOME/dotnet

然后查看安装情况

dotnet --info

如果返回了正确的运行时版本说明安装成功。

由于使用 export 命令只会使环境变量在当前会话生效,还需要根据你使用的 shell 修改对应的配置文件保证每次会话都能正常使用 dotnet 命令。请参考 在 Debian 上手动安装提示 部分进行配置。

偷偷告诉大家…我直接解压到 /usr/bin/dotnet 里面了,就不用配 bashrc 之类的了 😅

这期文章到这里就结束了,如果大家部署了好玩的站点别忘了通过微信公众号告诉我哦~

参考