using System.Collections.Concurrent;
using System.ComponentModel;
using System.Web;
using AngleSharp;
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 ConcurrentDictionary<
string,
CancellationTokenSource
> CancellationTokens = new();
/// <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>
/// 是否为ajax请求
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public static bool IsAjax(this HttpRequest request)
{
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, []);
}
private static bool TryConvertClaimValue(string raw, Type targetType, out object? value)
{
if (targetType == typeof(string))
{
value = raw;
return true;
}
var underlyingType = Nullable.GetUnderlyingType(targetType);
if (underlyingType != null)
{
if (string.IsNullOrWhiteSpace(raw))
{
value = null;
return true;
}
return TryConvertClaimValue(raw, underlyingType, out value);
}
if (targetType.IsEnum)
{
if (Enum.TryParse(targetType, raw, true, out var enumValue))
{
value = enumValue;
return true;
}
value = null;
return false;
}
if (targetType == typeof(DateTime))
{
if (
DateTime.TryParse(
raw,
CultureInfo.InvariantCulture,
DateTimeStyles.RoundtripKind,
out var date
)
)
{
value = date;
return true;
}
if (DateTime.TryParse(raw, out date))
{
value = date;
return true;
}
value = null;
return false;
}
if (targetType == typeof(Guid))
{
if (Guid.TryParse(raw, out var guid))
{
value = guid;
return true;
}
value = null;
return false;
}
var converter = TypeDescriptor.GetConverter(targetType);
if (converter.CanConvertFrom(typeof(string)))
{
try
{
value = converter.ConvertFromInvariantString(raw);
return true;
}
catch
{
// ignored, fallback below
}
}
try
{
value = Convert.ChangeType(raw, targetType, CultureInfo.InvariantCulture);
return true;
}
catch
{
value = null;
return false;
}
}
extension(ClaimsPrincipal? principal)
{
/// <summary>
/// 用户ID
/// </summary>
public string? UserId => principal?.FindFirst(ClaimTypes.NameIdentifier)?.Value;
/// <summary>
/// 严格获取用户ID
/// <exception cref="InvalidCredentialException">如果用户未登录,将会引发此异常</exception>
/// </summary>
public string RequiredUserId => principal?.UserId ?? throw new InvalidCredentialException();
/// <summary>
/// 用户信息
/// </summary>
public VmUserInfo? UserInfo => principal.GetUserInfo();
/// <summary>
/// 严格获取用户信息
/// <exception cref="InvalidCredentialException">如果用户未登录,将会引发此异常</exception>
/// </summary>
public VmUserInfo RequiredUserInfo =>
principal?.UserInfo ?? throw new InvalidCredentialException();
/// <summary>
/// 权限
/// </summary>
public Permissions? Permissions => principal.ParsePermissions();
/// <summary>
/// 是否具有系统权限
/// </summary>
public bool HasSystem => principal.HasSystemPermission();
private VmUserInfo? GetUserInfo()
{
if (principal is not { Authenticated: true })
{
return null;
}
var userInfo = VmUserInfo.Empty();
var writeableProperties = VmUserInfo.GetCanWriteProperties();
foreach (var claims in principal.Claims)
{
if (!writeableProperties.TryGetValue(claims.Type, out var property))
{
continue;
}
var setter = ApplicationTools.GetSetter<VmUserInfo>(property.Name);
if (setter == null)
{
continue;
}
if (
!TryConvertClaimValue(
claims.Value,
property.PropertyType,
out var convertedValue
)
)
{
continue;
}
setter(userInfo, convertedValue);
}
return userInfo;
}
private Permissions? ParsePermissions()
{
var permissionClaim = principal?.FindFirst("Permissions")?.Value;
if (permissionClaim is null)
{
return null;
}
if (Enum.TryParse<Permissions>(permissionClaim, ignoreCase: true, out var permissions))
{
return permissions;
}
return null;
}
private bool HasSystemPermission()
{
var permissions = principal?.ParsePermissions();
return permissions.HasValue
&& (permissions.Value & Permissions.System) == Permissions.System;
}
/// <summary>
/// 是否已认证
/// </summary>
public bool Authenticated => principal?.Identity?.IsAuthenticated == true;
}
}
⚠⚠ 以下内容为AI分析的结果,请根据实际情况进行判断。
上述代码是一个 C# 类库,名为 WebToolsExtensions,它包含了一系列的扩展方法和工具函数,主要用于 ASP.NET Core Web 应用程序的开发。以下是对代码中各个部分功能的详细解释:
1. 常量和字段
- Version: 获取当前应用程序的版本。
- DefaultGroupId: 定义一个默认的组 ID。
- Wind: 一个字典,映射风速等级到中文描述。
- StartTime: 系统启动时间的静态字段。
2. 用户身份相关方法
- GetIdentity: 从
ClaimsPrincipal中提取用户信息,返回一个VmUserInfo对象。如果用户未登录,则返回null。 - GetStrictIdentity: 获取用户身份信息,如果未登录则抛出
InvalidCredentialException。 - GetIdentity (HttpContext): 根据提供的
TokenManagement验证 JWT 令牌并获取用户身份信息。 - ValidationJwtBearer: 验证 JWT 令牌的有效性,设置
HttpContext.User。 - GetIdentity (Controller): 从控制器的
ViewData中获取当前用户信息。
3. 权限和登录状态检查
- IsAdmin: 检查当前用户是否具有管理员权限。
- IsLogin: 检查用户是否已登录。
4. 请求和会话相关方法
- GetUserInfo: 获取当前用户信息,基于 Cookie 认证。
- SessionId: 获取当前会话 ID。
- GetIpAddress: 获取请求的 IP 地址,支持 X-Forwarded-For 头。
5. 视图和 AJAX 相关方法
- SetTitle: 设置页面标题。
- IsAjax: 检查请求是否为 AJAX 请求。
6. 文章标签和枚举描述
- ArticleTagsAsync: 异步获取文章标签并返回
SelectListItem列表。 - GetDescription: 获取枚举值的描述属性。
7. 文件大小格式化
- FileSize: 将文件大小(以字节为单位)格式化为可读的字符串(如 KB、MB、GB)。
8. 控制器公共操作
- GetPublicAction: 获取所有公共控制器操作的方法,返回一个字典,键为控制器名称,值为方法名称列表。
9. 网页数据源转换
- ToGridManagerSource: 将分页列表转换为适合 GridManager 的数据源格式。
10. HTML 清理和 Markdown 转换
- CustomHtmlSanitizer: 创建一个自定义的 HTML 清理器,基于配置文件中的规则。
- ClearLinkAsync: 将 Markdown 内容转换为 HTML,并清理链接,确保在新标签页中打开。
11. URI 处理
- ForceHttps: 将给定的 URL 强制转换为 HTTPS。
12. 音乐文件删除
- DeleteMusicAsync: 异步删除音乐及其相关文件(封面、歌词)。
13. 配置获取
- GetUpyunHost: 从配置中获取 Upyun 的主机地址。
14. 模型状态检查
- CheckModelState: 检查模型状态是否有效,并返回相应的结果。
总结
这个类库提供了多种实用的扩展方法,旨在简化 ASP.NET Core Web 应用程序中的常见任务,如用户身份验证、请求处理、数据格式化、HTML 清理等。通过这些工具,开发人员可以更高效地构建和维护 Web 应用程序。
评论加载中...