using Dpz.Core.Public.Entity.Option;
using Dpz.Core.Public.ViewModel.Option;
namespace Dpz.Core.Service.RepositoryServiceImpl;
public class AppOptionService(IRepository<AppOption> repository, IMapper mapper) : IAppOptionService
{
/// <summary>
/// 友情链接 Option name
/// </summary>
private const string FriendOptionName = "friends";
/// <summary>
/// 页脚内容 Option name
/// </summary>
private const string FooterContentOptionName = "footer";
/// <summary>
/// robots.txt Option name
/// </summary>
private const string RobotsOptionName = "robots.txt";
[Cache(ExpirationSeconds = 30 * ExpirationTime.Day)]
public async Task<IList<VmFriends>> GetFriendsAsync()
{
var friends = await repository
.SearchFor(x => x.OptionName == FriendOptionName)
.ToListAsync();
if (friends == null || friends.Count == 0)
{
return [];
}
var list = friends.Cast<Friends>().ToList();
return mapper.Map<List<VmFriends>>(list);
}
[InvalidateCache(Methods = [nameof(GetFriendsAsync)])]
public async Task AddFriendAsync(VmFriends friend)
{
var entity = mapper.Map<Friends>(friend);
entity.CreateTime = DateTime.Now;
entity.LastUpdateTime = DateTime.Now;
entity.OptionName = FriendOptionName;
await repository.InsertAsync(entity);
}
[InvalidateCache(Methods = [nameof(GetFriendsAsync)])]
public async Task EditFriendAsync(VmFriends? friend)
{
if (string.IsNullOrEmpty(friend?.Id) || !ObjectId.TryParse(friend.Id, out var oid))
{
return;
}
var entity = await repository.FindAsync(oid);
if (entity == null || entity is not Friends entityFriend)
{
return;
}
entityFriend.Avatar = friend.Avatar;
entityFriend.Description = friend.Description;
entityFriend.Link = friend.Link;
entityFriend.Name = friend.Name;
entityFriend.LastUpdateTime = DateTime.Now;
await repository.UpdateAsync(entityFriend);
}
public async Task<VmAppOption?> FindAsync(string id)
{
var entity = await repository.TryGetAsync(id);
if (entity == null)
{
return null;
}
return mapper.Map<VmAppOption>(entity);
}
[InvalidateCache(Methods = [nameof(GetFooterContentAsync)])]
public async Task SaveFooterContentAsync(string content)
{
var footer = await repository
.SearchFor(x => x.OptionName == FooterContentOptionName)
.FirstOrDefaultAsync();
if (footer != null)
{
var set = new BsonDocument
{
{
"$set",
new BsonDocument
{
{ nameof(FooterContent.Content), new BsonString(content) },
{ nameof(FooterContent.LastUpdateTime), new BsonDateTime(DateTime.Now) },
}
},
};
UpdateDefinition<AppOption> update = new BsonDocumentUpdateDefinition<AppOption>(set);
await repository.UpdateAsync(x => x.Id == footer.Id, update);
return;
}
var entity = new FooterContent
{
Content = content,
CreateTime = DateTime.Now,
LastUpdateTime = DateTime.Now,
OptionName = FooterContentOptionName,
};
await repository.InsertAsync(entity);
}
[Cache(ExpirationSeconds = 30 * ExpirationTime.Day)]
public async Task<string> GetFooterContentAsync()
{
var footer = await repository
.SearchFor(x => x.OptionName == FooterContentOptionName)
.FirstOrDefaultAsync();
return footer is FooterContent entity ? entity.Content ?? "" : "";
}
[Cache(ExpirationSeconds = 30 * ExpirationTime.Day)]
public async Task<string> GetRobotsAsync()
{
var robots = await repository
.SearchFor(x => x.OptionName == RobotsOptionName)
.SingleOrDefaultAsync();
return robots is RobotsOption entity ? entity.Content : "";
}
[InvalidateCache(Methods = [nameof(GetRobotsAsync)])]
public async Task SaveRobotsAsync(string content)
{
var robots = await repository
.SearchFor(x => x.OptionName == RobotsOptionName)
.FirstOrDefaultAsync();
if (robots != null)
{
var set = new BsonDocument
{
{
"$set",
new BsonDocument
{
{ nameof(RobotsOption.Content), new BsonString(content) },
{ nameof(RobotsOption.LastUpdateTime), new BsonDateTime(DateTime.Now) },
}
},
};
UpdateDefinition<AppOption> update = new BsonDocumentUpdateDefinition<AppOption>(set);
await repository.UpdateAsync(x => x.Id == robots.Id, update);
return;
}
var entity = new RobotsOption
{
Content = content,
CreateTime = DateTime.Now,
LastUpdateTime = DateTime.Now,
OptionName = RobotsOptionName,
};
await repository.InsertAsync(entity);
}
[InvalidateCache(Methods = [nameof(GetFriendsAsync)])]
public async Task DeleteFriendAsync(string id)
{
if (ObjectId.TryParse(id, out var oid))
{
await repository.DeleteAsync(x => x.OptionName == FriendOptionName && x.Id == oid);
}
}
}
⚠⚠ 以下内容为AI分析的结果,请根据实际情况进行判断。
代码解释
这是一个 应用选项服务类 (AppOptionService),用于管理应用程序的各种配置选项,如友情链接、页脚内容和 robots.txt 文件。
核心功能
1. 类结构
public class AppOptionService(IRepository<AppOption> repository, IMapper mapper) : IAppOptionService
- 使用 主构造函数 (C# 12 特性) 注入依赖
repository: 数据仓储,用于数据库操作mapper: 对象映射器 (AutoMapper),用于实体和视图模型之间的转换
2. 常量定义
private const string FriendOptionName = "friends"; // 友情链接标识
private const string FooterContentOptionName = "footer"; // 页脚内容标识
private const string RobotsOptionName = "robots.txt"; // robots.txt标识
主要方法
📌 友情链接管理
GetFriendsAsync() - 获取友情链接
[Cache(ExpirationSeconds = 30 * ExpirationTime.Day)]
- 使用 缓存 (30天过期)
- 查询所有
OptionName == "friends"的记录 - 将实体转换为
VmFriends视图模型返回
AddFriendAsync() - 添加友情链接
- 使用
[InvalidateCache]特性使GetFriendsAsync的缓存失效 - 映射视图模型到实体,设置创建/更新时间
- 插入数据库
EditFriendAsync() - 编辑友情链接
- 验证 ID 格式 (MongoDB ObjectId)
- 查找并更新实体的各个属性 (头像、描述、链接、名称)
- 更新最后修改时间
DeleteFriendAsync() - 删除友情链接
- 验证 ObjectId 格式
- 按
OptionName和Id删除记录
📌 页脚内容管理
GetFooterContentAsync() - 获取页脚内容
- 30天缓存
- 查询
OptionName == "footer"的记录 - 类型转换为
FooterContent并返回内容
SaveFooterContentAsync() - 保存页脚内容
- 使缓存失效
- 如果记录存在:使用 MongoDB BSON 更新文档 直接更新字段
- 如果不存在:创建新记录
📌 Robots.txt 管理
GetRobotsAsync() - 获取 robots.txt
- 30天缓存
- 查询并返回
RobotsOption内容
SaveRobotsAsync() - 保存 robots.txt
- 逻辑与
SaveFooterContentAsync类似 - 使用 BSON 更新或插入新记录
📌 通用方法
FindAsync() - 查找单个选项
- 根据 ID 查找任意
AppOption - 返回映射后的
VmAppOption视图模型
技术特点
1. 缓存策略
- 使用 AOP 缓存特性 (
[Cache]和[InvalidateCache]) - 读操作缓存 30 天
- 写操作自动清除相关缓存
2. MongoDB 特性
- 使用
ObjectId作为主键 - 使用 BsonDocument 构建原生更新语句:
var set = new BsonDocument
{
{ "$set", new BsonDocument { /* 字段更新 */ } }
};
3. 数据一致性
- 所有修改操作都更新
LastUpdateTime - 新增操作同时设置
CreateTime和LastUpdateTime
4. 类型安全
- 使用模式匹配检查实体类型 (
is Friends,is FooterContent) - 使用
ObjectId.TryParse验证 ID 格式
应用场景
这个服务适用于 CMS 系统 或 博客系统,管理如下配置:
- 友情链接列表
- 网站页脚自定义内容
- SEO 相关的 robots.txt 文件
AI 正在分析代码…
评论加载中...