using Dpz.Core.Public.ViewModel.Sitemaps;
namespace Dpz.Core.Service.RepositoryServiceImpl;
/// <summary>
/// 站点地图存储服务
/// </summary>
public class SitemapService(IRepository<SitemapDocument> repository, IMapper mapper)
: ISitemapService
{
/// <inheritdoc />
[Cache(ExpirationSeconds = ExpirationTime.Day, Prefix = "sitemap")]
public async Task<VmSitemapFile?> GetLatestAsync(
string name,
CancellationToken cancellationToken = default
)
{
var filter = Builders<SitemapDocument>.Filter.Eq(x => x.Name, name);
var cursor = await repository
.SearchFor(filter)
.SortByDescending(x => x.Date)
.Limit(1)
.ToCursorAsync(cancellationToken);
var entity = await cursor.FirstOrDefaultAsync(cancellationToken);
if (entity == null)
{
return null;
}
return mapper.Map<VmSitemapFile>(entity);
}
/// <inheritdoc />
[InvalidateCache(Methods = [nameof(GetLatestAsync)])]
public async Task SaveAsync(
IReadOnlyCollection<VmSitemapFile> files,
CancellationToken cancellationToken = default
)
{
var entities = files
.Select(file => new SitemapDocument
{
Name = file.Name,
Date = DateTime.Now,
Xml = file.Xml,
UrlCount = file.UrlCount,
ByteCount = Encoding.UTF8.GetByteCount(file.Xml),
})
.ToList();
await repository.InsertAsync(entities, cancellationToken);
}
}
⚠⚠ 以下内容为AI分析的结果,请根据实际情况进行判断。
这段代码是一个基于 C# 的站点地图(Sitemap)存储服务实现,主要用于将站点地图数据保存到 MongoDB,并支持缓存和查询最新版本。下面我会逐步解释代码的各个部分。
1. 命名空间与类声明
using Dpz.Core.Public.ViewModel.Sitemaps;
namespace Dpz.Core.Service.RepositoryServiceImpl;
- 引入
Dpz.Core.Public.ViewModel.Sitemaps,说明VmSitemapFile这个视图模型位于该命名空间。 - 当前类所在的命名空间是
Dpz.Core.Service.RepositoryServiceImpl,通常表明这是仓储接口的一个具体实现。
public class SitemapService(IRepository<SitemapDocument> repository, IMapper mapper)
: ISitemapService
- 类
SitemapService继承自ISitemapService接口,并提供具体实现。 - 使用了主构造函数(C# 12 特性),直接在参数列表中注入两个依赖:
IRepository<SitemapDocument>:泛型仓储,用于操作SitemapDocument文档。IMapper:AutoMapper 或类似的对象映射器,用于将实体转换为视图模型。
- 这种写法省去了显式的字段声明和构造器赋值,编译器会隐式生成对应的私有字段。
2. 获取最新站点地图
[Cache(ExpirationSeconds = ExpirationTime.Day, Prefix = "sitemap")]
public async Task<VmSitemapFile?> GetLatestAsync(
string name,
CancellationToken cancellationToken = default
)
[Cache]特性表示这个方法的结果会被缓存,缓存过期时间设置为ExpirationTime.Day(假设是一天),缓存键前缀为"sitemap"。- 方法接收一个
name(站点地图名称,比如sitemap.xml)和一个可选的取消令牌。
方法内部逻辑:
var filter = Builders<SitemapDocument>.Filter.Eq(x => x.Name, name);
- 使用 MongoDB 的
Builders<SitemapDocument>.Filter构建过滤条件,查询Name字段等于传入name的文档。
var cursor = await repository
.SearchFor(filter)
.SortByDescending(x => x.Date)
.Limit(1)
.ToCursorAsync(cancellationToken);
- 通过仓储的
SearchFor方法执行查询,按Date字段降序排序,只取第一条(最新的记录),然后转换为异步游标。 SortByDescending(x => x.Date)表示按日期从新到旧排列,这样第一条就是最新版本。
var entity = await cursor.FirstOrDefaultAsync(cancellationToken);
if (entity == null)
{
return null;
}
return mapper.Map<VmSitemapFile>(entity);
- 从游标中读取第一个实体(或默认值)。
- 如果为空,返回
null,表示没有找到对应名称的站点地图。 - 否则使用
IMapper将SitemapDocument实体映射为VmSitemapFile视图模型并返回。
3. 保存站点地图
[InvalidateCache(Methods = [nameof(GetLatestAsync)])]
public async Task SaveAsync(
IReadOnlyCollection<VmSitemapFile> files,
CancellationToken cancellationToken = default
)
[InvalidateCache]特性表明在执行此方法后,需要使指定的缓存项失效。Methods参数明确指向GetLatestAsync方法,即保存新数据后,会清除之前缓存的“最新”数据,避免下次获取到旧缓存。- 方法接收一个
IReadOnlyCollection<VmSitemapFile>集合,用于批量保存。
方法内部逻辑:
var entities = files
.Select(file => new SitemapDocument
{
Name = file.Name,
Date = DateTime.Now,
Xml = file.Xml,
UrlCount = file.UrlCount,
ByteCount = Encoding.UTF8.GetByteCount(file.Xml),
})
.ToList();
- 将每个
VmSitemapFile转换成SitemapDocument实体:Name:站点地图文件名。Date:当前时间,作为保存时间戳。Xml:xml 内容的字符串。UrlCount:URL 数量。ByteCount:计算 XML 字符串按 UTF-8 编码后的字节数大小。
await repository.InsertAsync(entities, cancellationToken);
- 调用仓储的异步插入方法,将所有实体批量写入数据库。
4. 整体设计解读
- 仓储模式:通过
IRepository<T>抽象了数据库访问,使得上层服务无需关心 MongoDB 具体操作细节。 - 缓存策略:使用
[Cache]和[InvalidateCache]特性,实现了查询结果缓存和写入后自动失效,提升了读取性能。 - 文档存储:每个站点地图快照作为一条独立文档存储,
Name用于区分不同文件,Date用于标识版本。 - 版本历史:由于不会覆盖旧记录,每次保存都会新增一条记录,通过查询最新日期即可取出当前有效版本,同时保留了历史版本(如果需要回溯)。
- 数据流量优化:记录
ByteCount可以快速获知 XML 大小,便于统计或限制,而无需每次重新计算。 - 异步安全:方法均支持
CancellationToken,符合现代响应式应用的要求。
总的来说,这是一个典型的“按名字存取最新站点地图”的服务实现,利用了缓存和 MongoDB 的灵活查询特性,适合用于 SEO 站点地图的生成与发布场景。
AI 正在分析代码…
评论加载中...