using System.Collections.Specialized;
using System.Net.Http;
using System.Threading;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Dpz.Core.Service;
public interface IBingWallpaper
{
/// <summary>
/// 随机获取一张壁纸
/// </summary>
/// <returns></returns>
Task<Wallpaper> GetRandomWallpaperAsync();
/// <summary>
/// 获取今日的所有壁纸
/// </summary>
/// <returns></returns>
Task<List<Wallpaper>> GetTodayWallpapersAsync();
/// <summary>
/// 清除缓存
/// </summary>
/// <returns></returns>
Task ClearCacheAsync();
}
public class Wallpaper
{
private const string Host = "https://cn.bing.com";
private string _url = "";
[JsonProperty("url")]
public string Url
{
get => _url.StartsWith("http", StringComparison.OrdinalIgnoreCase) ? _url : Host + _url;
set => _url = value;
}
[JsonProperty("copyright")]
public string? CopyRight { get; set; }
[JsonProperty("copyrightlink")]
public string? CopyRightLink { get; set; }
}
public class BingWallpaper(
ILogger<BingWallpaper> logger,
IHttpClientFactory httpClientFactory,
IFusionCache fusionCache
) : AbstractCacheService(fusionCache), IBingWallpaper
{
private readonly Wallpaper _defaultWallpaper =
new()
{
Url =
"/th?id=OHR.RedAlley_ZH-CN2795378972_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp",
CopyRight = "武侯祠内红墙和竹林掩映下的小巷,中国成都 (© Eastimages/Getty Images)",
CopyRightLink =
"https://www.bing.com/search?q=%E6%AD%A6%E4%BE%AF%E7%A5%A0&form=hpcapt&mkt=zh-cn",
};
private async Task<List<Wallpaper>> FetchWallpaperAsync(
CancellationToken cancellationToken = default
)
{
try
{
//var request = new RestRequest("/HPImageArchive.aspx", Method.GET);
var parameters = new NameValueCollection
{
{ "format", "js" },
//请求图片截止天数 0 今天 -1 截止中明天 (预准备的) 1 截止至昨天,类推(目前最多获取到7天前的图片)
{ "idx", "0" },
//1-8 返回请求数量,目前最多一次获取8张
{ "n", "8" },
//地区
{ "mkt", "zh-CN" },
};
var httpClient = httpClientFactory.CreateClient("edge");
var request = new HttpRequestMessage(
HttpMethod.Get,
$"https://cn.bing.com/HPImageArchive.aspx?{parameters.ToQueryString()}"
);
var response = await httpClient.SendAsync(request, cancellationToken);
var content = await response.Content.ReadAsStringAsync(cancellationToken);
var result = JObject.Parse(content)["images"]?.ToObject<List<Wallpaper>>() ?? [];
return result;
}
catch (Exception e)
{
logger.LogError(e, "获取bing壁纸失败");
var result = new List<Wallpaper> { _defaultWallpaper };
return result;
}
}
private async Task<List<Wallpaper>> GetWallpaperAsync()
{
return await GetOrSetCacheAsync<List<Wallpaper>>(
nameof(GetWallpaperAsync),
(_, cancellationToken) => FetchWallpaperAsync(cancellationToken)
);
}
public async Task<Wallpaper> GetRandomWallpaperAsync()
{
return await GetOrSetCacheAsync<Wallpaper>(
nameof(GetRandomWallpaperAsync),
async (_, _) =>
{
var list = await GetWallpaperAsync();
var result = list.OrderBy(_ => Guid.NewGuid()).FirstOrDefault();
return result ?? _defaultWallpaper;
}
);
}
public async Task<List<Wallpaper>> GetTodayWallpapersAsync()
{
return await GetWallpaperAsync();
}
public async Task ClearCacheAsync()
{
await RemoveByPrefixAsync();
}
protected override TimeSpan CacheDefaultExpiration => TimeSpan.FromDays(1);
}
⚠⚠ 以下内容为AI分析的结果,请根据实际情况进行判断。
下面按模块逐项说明这段代码的功能与行为(中文说明):
总体
- 定义了一个用于获取必应壁纸的服务接口 IBingWallpaper 及其实现 BingWallpaper。
- 服务通过 HTTP 调用必应的 HPImageArchive.aspx 接口获取壁纸数据,并将结果以 Wallpaper 实体表示。
- 实现包含缓存逻辑(继承自 AbstractCacheService,使用注入的 IFusionCache),并在请求失败时返回一个内置的默认壁纸。
接口 IBingWallpaper
- Task
GetRandomWallpaperAsync():随机返回一张壁纸。 - Task<List
> GetTodayWallpapersAsync():返回当天(最多最近 8 张)所有壁纸列表。 - Task ClearCacheAsync():清除缓存。
实体 Wallpaper
- 三个属性:
- Url(映射 JSON 的 "url"):如果值是相对路径(非以 http 开头),会自动在前面拼接 Host 常量 "https://cn.bing.com" 以形成完整 URL。
- CopyRight(映射 JSON 的 "copyright"):版权说明文字。
- CopyRightLink(映射 JSON 的 "copyrightlink"):版权链接。
- JsonProperty 特性用于与返回的 JSON 字段名映射。
实现类 BingWallpaper
- 依赖注入的构造参数(通过构造器注入):ILogger
logger、IHttpClientFactory httpClientFactory、IFusionCache fusionCache。 - 继承自 AbstractCacheService,利用其提供的缓存方法(如 GetOrSetCacheAsync、RemoveByPrefixAsync);并重写 CacheDefaultExpiration 为 1 天。
FetchWallpaperAsync(私有方法)
- 构建请求参数:
- format=js(返回 JSON)
- idx=0(起始天数;0 当天,-1 明天等)
- n=8(请求数量,最多 8 张)
- mkt=zh-CN(地区)
- 使用 IHttpClientFactory 创建名为 "edge" 的 HttpClient,并对 https://cn.bing.com/HPImageArchive.aspx 发起 GET 请求(带上 query)。
- 读取响应内容并解析为 JSON,然后取 images 节点并转换为 List
返回(若解析为空则返回空列表或后续处理的默认值)。 - 在捕获到异常时记录日志(logger.LogError)并返回一个包含内置默认壁纸的列表作为兜底。
GetWallpaperAsync(私有)
- 使用缓存方法 GetOrSetCacheAsync 将 FetchWallpaperAsync 的结果缓存(缓存键为 nameof(GetWallpaperAsync)),避免每次都发起网络请求。
GetRandomWallpaperAsync
- 通过缓存键 nameof(GetRandomWallpaperAsync) 获取或设置缓存:
- 从 GetWallpaperAsync 获取列表,然后随机选一张(实现是 list.OrderBy(_ => Guid.NewGuid()).FirstOrDefault() 的方式来打乱顺序并取第一个)。
- 若列表为空则返回内置默认壁纸。
GetTodayWallpapersAsync
- 直接返回 GetWallpaperAsync 的结果(即当天的壁纸列表,且受缓存控制)。
ClearCacheAsync
- 调用 RemoveByPrefixAsync() 清除缓存(AbstractCacheService 提供的删除机制,通常是按前缀删除所有相关缓存项)。
其他细节
- 默认壁纸 _defaultWallpaper:当从网络获取失败或没有数据时作为兜底项,注意它的 Url 是以相对路径形式给出,Wallpaper.Url getter 会自动拼接 Host 变成完整 URL。
- HTTP 客户端是通过 IHttpClientFactory 创建并使用名为 "edge" 的客户端(配置可能在外部启动代码中定义)。
- 方法内部对 CancellationToken 有支持(FetchWallpaperAsync 可接受 cancellationToken 并将其传给 SendAsync / ReadAsStringAsync)。
总结
- 这个类封装了从必应获取当天壁纸、缓存结果、提供随机壁纸及清理缓存的功能;在出错时会返回一个预置的默认壁纸并记录错误日志。
评论加载中...