using System.ComponentModel;
using System.Web;
using AngleSharp;
using Dpz.Core.Entity.Base;
using Dpz.Core.EnumLibrary;
using Dpz.Core.Public.ViewModel.Response;
using Dpz.Core.Service.ObjectStorage.Services;
using Markdig;
using Microsoft.AspNetCore.Mvc.ModelBinding;

#pragma warning disable CS0162

namespace Dpz.Core.Web.Library;

public static class WebToolsExtensions
{
    public const string DefaultGroupId = "5e09be6ae22e4d3b7810b6c7";

    public static readonly Dictionary<int, string> Wind = new()
    {
        { 0, "静风" },
        { 1, "软风" },
        { 2, "轻风" },
        { 3, "微风" },
        { 4, "和风" },
        { 5, "清风" },
        { 6, "强风" },
        { 7, "疾风" },
        { 8, "大风" },
        { 9, "强大风" },
        { 10, "超强大风" },
        { 11, "暴风" },
        { 12, "飓风" },
    };

    /// <summary>
    /// 系统启动时间
    /// </summary>
    public static readonly DateTime StartTime = new(2018, 2, 11, 13, 56, 24, DateTimeKind.Local);

    /// <summary>
    /// 设置标题
    /// </summary>
    /// <param name="controller"></param>
    /// <param name="title"></param>
    public static void SetTitle(this Controller controller, string title)
    {
        controller.ViewData["Title"] = $"{title} - 叫我阿胖";
    }

    /// <summary>
    /// 判断客户端是否期望 JSON 响应
    /// </summary>
    /// <param name="request"></param>
    /// <returns></returns>
    public static bool ExpectsJsonResponse(this HttpRequest request)
    {
        // 检查 Accept 头,客户端期望 JSON 响应
        var accept = request.Headers.Accept.ToString();
        if (accept.Contains("application/json", StringComparison.OrdinalIgnoreCase))
        {
            return true;
        }

        // 检查 Content-Type,请求体是 JSON
        var contentType = request.ContentType;
        if (contentType?.Contains("application/json", StringComparison.OrdinalIgnoreCase) == true)
        {
            return true;
        }

        // 保持对老式 AJAX 请求的兼容性
        var with = request.Headers["X-Requested-With"];
        return string.Equals(with, "XMLHttpRequest", StringComparison.OrdinalIgnoreCase);
    }

    /// <summary>
    /// 获取枚举描述
    /// </summary>
    /// <param name="e"></param>
    /// <returns></returns>
    public static string GetDescription(this Enum e)
    {
        var value = e.ToString();
        var attribute = e.GetType().GetField(value)?.GetCustomAttribute<DescriptionAttribute>();
        return attribute?.Description ?? "";
    }

    /// <summary>
    /// 显示文件可读大小
    /// </summary>
    /// <param name="length"></param>
    /// <returns></returns>
    public static string FileSize(this long length)
    {
        var sizeText = length + " bytes";
        if (length > 1024m && length < 1024m * 1024m * 3)
        {
            sizeText = (length / 1024m).ToString("F") + " KB";
        }
        else if (length > 1024m * 1024m * 3 && length < 1024m * 1024m * 1024m)
        {
            sizeText = (length / 1024m / 1024m).ToString("F") + " MB";
        }
        else if (length > 1024m * 1024m * 1024m)
        {
            sizeText = (length / 1024m / 1024m / 1024m).ToString("F") + " GB";
        }

        return sizeText;
    }

    /// <summary>
    /// 从markdown转成html,并从html内容中清除链接的跳转平台,并且在新标签页打开
    /// </summary>
    /// <param name="content"></param>
    /// <returns></returns>
    public static async Task<string> ClearLinkAsync(this string content)
    {
        var pipeline = new MarkdownPipelineBuilder()
            .UsePipeTables()
            .UseTaskLists()
            .UseEmphasisExtras()
            .UseAutoIdentifiers()
            .UseAdvancedExtensions()
            .DisableHtml()
            .Build();
        var detail = Markdown.ToHtml(content, pipeline);
        var context = BrowsingContext.New(Configuration.Default);
        var document = await context.OpenAsync(y => y.Content(detail));
        var images = document.GetElementsByTagName("img");
        foreach (var image in images)
        {
            var src = image.GetAttribute("src");
            image.SetAttribute("class", "lazy");
            image.SetAttribute("loading", "lazy");
            image.SetAttribute("src", $"{Program.LibraryHost}/loaders/bars.svg");
            image.SetAttribute("data-src", src ?? $"{Program.AssetsHost}/images/notfound.png");
        }

        var links = document.GetElementsByTagName("a");
        foreach (var item in links)
        {
            var href = item.GetAttribute("href");
            if (href != null)
            {
                var uri = new Uri(href);
                var parameters = HttpUtility.ParseQueryString(uri.Query);
                var target = parameters["target"];
                if (!string.IsNullOrEmpty(target))
                {
                    item.SetAttribute("href", target);
                }

                item.SetAttribute("target", "_blank");
            }
        }

        return document.Body?.InnerHtml ?? "";
    }

    public static async Task DeleteMusicAsync(
        this IObjectStorageOperation objectStorageService,
        MusicResponse musicResponse
    )
    {
        if (musicResponse == null)
        {
            throw new ArgumentNullException(nameof(musicResponse));
        }
        if (string.IsNullOrEmpty(musicResponse.MusicUrl))
        {
            throw new ArgumentException(
                "property MusicUrl is empty or null",
                nameof(musicResponse.MusicUrl)
            );
        }

        await objectStorageService.DeleteAsync(musicResponse.MusicUrl);

        if (!string.IsNullOrEmpty(musicResponse.CoverUrl))
        {
            await objectStorageService.DeleteAsync(musicResponse.CoverUrl);
        }

        if (!string.IsNullOrEmpty(musicResponse.LyricUrl))
        {
            await objectStorageService.DeleteAsync(musicResponse.LyricUrl);
        }
    }

    public static ModelStateResult CheckModelState(this ModelStateDictionary modelState)
    {
        if (modelState.IsValid)
        {
            var messages = modelState
                .SelectMany(x => x.Value?.Errors ?? new ModelErrorCollection())
                .Select(x => x.ErrorMessage)
                .Where(x => !string.IsNullOrEmpty(x))
                .ToList();
            if (messages.Count == 0)
            {
                return new ModelStateResult(false, []);
            }

            return new ModelStateResult(true, messages);
        }

        return new ModelStateResult(false, []);
    }
}
⚠⚠    以下内容为AI分析的结果,请根据实际情况进行判断。

代码解释

这是一个 C# 静态扩展类 WebToolsExtensions,包含了多个工具方法和常量,用于 ASP.NET Core Web 应用程序。以下是详细解释:

常量定义

  1. DefaultGroupId: 默认分组ID字符串
  2. Wind: 风力等级字典(0-12级,对应中文描述)
  3. StartTime: 系统启动时间(2018年2月11日)

扩展方法

1. SetTitle

为控制器设置页面标题,格式为 "{title} - 叫我阿胖"

2. ExpectsJsonResponse

判断HTTP请求是否期望JSON响应,通过检查:

  • Accept 头是否包含 "application/json"
  • Content-Type 是否为 JSON
  • X-Requested-With 是否为 "XMLHttpRequest"(兼容旧式AJAX)

3. GetDescription

获取枚举值的 DescriptionAttribute 描述文本

4. FileSize

将字节数转换为可读的文件大小格式:

  • < 3MB: 显示为 KB
  • 3MB - 1GB: 显示为 MB
  • > 1GB: 显示为 GB

5. ClearLinkAsync

处理 Markdown 内容:

  • 使用 Markdig 将 Markdown 转换为 HTML
  • 使用 AngleSharp 解析 HTML
  • 为图片添加懒加载属性(lazy loading)
  • 设置图片占位符
  • 修改链接在新标签页打开
  • 清理链接中的跳转平台参数

6. DeleteMusicAsync

删除音乐相关的对象存储文件:

  • 删除音乐文件(必需)
  • 删除封面图片(如果存在)
  • 删除歌词文件(如果存在)
  • 包含参数验证

7. CheckModelState

检查 ASP.NET Core 的模型状态验证结果:

  • 提取所有验证错误消息
  • 返回 ModelStateResult 对象包含验证状态和错误列表

技术特点

  • 使用扩展方法模式增强现有类型功能
  • 集成第三方库(Markdig、AngleSharp)
  • 支持异步操作
  • 包含空值检查和参数验证
  • 禁用了 CS0162 编译警告(可能存在不可达代码)
评论加载中...