CMS 概述
Biwen.QuickApi 的 CMS 模块提供了一个灵活的内容管理系统,支持多种内容类型和自定义字段。
基本概念
1. 内容类型
内容类型是 CMS 的核心概念,它定义了内容的结构和行为:
[Description("文章")]
public class Article : ContentBase<Article>
{
[Display(Name = "标题")]
[Required]
public TextFieldType Title { get; set; } = null!;
[Display(Name = "内容")]
[MarkdownToolBar(MarkdownToolStyle.Standard)]
public MarkdownFieldType? Content { get; set; }
[Display(Name = "发布日期")]
public DateTimeFieldType? PublishDate { get; set; }
public override string Content_Description => "文章内容";
}
2. 字段类型
CMS 支持多种字段类型:
- 文本字段(
TextFieldType
) - 富文本字段(
MarkdownFieldType
) - 日期字段(
DateTimeFieldType
) - 数字字段(
NumberFieldType
) - 选择字段(
OptionsFieldType
) - 媒体字段(
MediaFieldType
)
使用方式
1. 基本配置
在 Program.cs
中配置 CMS:
builder.Services.AddBiwenContents(options =>
{
options.EnableVersioning = true;
options.EnableAuditLog = true;
options.MaxPageSize = 100;
});
2. 内容管理
使用 IContentRepository
管理内容:
public class ArticleService
{
private readonly IContentRepository _repository;
private readonly ILogger<ArticleService> _logger;
public ArticleService(
IContentRepository repository,
ILogger<ArticleService> logger)
{
_repository = repository;
_logger = logger;
}
public async Task<Article> CreateArticleAsync(CreateArticleDto dto)
{
try
{
var content = new Content
{
ContentType = typeof(Article).FullName,
Title = dto.Title,
Slug = dto.Slug,
Status = ContentStatus.Draft
};
var article = content.ToContent<Article>();
article.Title.Value = dto.Title;
article.Content.Value = dto.Content;
article.PublishDate.Value = DateTime.UtcNow;
await _repository.CreateAsync(content);
return article;
}
catch (Exception ex)
{
_logger.LogError(ex, "创建文章失败");
throw;
}
}
}
高级特性
1. 版本控制
CMS 支持内容版本控制:
public class ArticleService
{
private readonly IContentRepository _repository;
private readonly ILogger<ArticleService> _logger;
public ArticleService(
IContentRepository repository,
ILogger<ArticleService> logger)
{
_repository = repository;
_logger = logger;
}
public async Task<Article> GetVersionAsync(Guid contentId, int version)
{
var versionContent = await _repository.GetVersionAsync(contentId, version);
if (versionContent == null)
{
throw new VersionNotFoundException(contentId, version);
}
return versionContent.ToContent<Article>();
}
public async Task<IEnumerable<ContentVersion>> GetVersionsAsync(Guid contentId)
{
return await _repository.GetVersionsAsync(contentId);
}
}
最佳实践
内容设计
- 合理设计内容类型
- 使用适当的字段类型
- 考虑内容的扩展性
性能优化
- 使用缓存
- 优化查询
- 批量处理内容
安全考虑
- 实现访问控制
- 验证内容
- 保护敏感信息
示例
1. 文章管理示例
[QuickApi("articles")]
public class ArticleApi : BaseQuickApi
{
private readonly IContentRepository _repository;
private readonly ILogger<ArticleApi> _logger;
public ArticleApi(
IContentRepository repository,
ILogger<ArticleApi> logger)
{
_repository = repository;
_logger = logger;
}
public async Task<Article> Get(Guid id)
{
var content = await _repository.GetByIdAsync(id);
if (content == null)
{
throw new ContentNotFoundException(id);
}
return content.ToContent<Article>();
}
[HttpPost]
public async Task<Result> Create([FromBody] CreateArticleDto dto)
{
try
{
var content = new Content
{
ContentType = typeof(Article).FullName,
Title = dto.Title,
Slug = dto.Slug,
Status = ContentStatus.Draft
};
var article = content.ToContent<Article>();
article.Title.Value = dto.Title;
article.Content.Value = dto.Content;
article.PublishDate.Value = DateTime.UtcNow;
await _repository.CreateAsync(content);
return Result.Success();
}
catch (Exception ex)
{
_logger.LogError(ex, "创建文章失败");
return Result.Fail("创建文章失败");
}
}
}
2. 内容查询示例
public class ContentQueryService
{
private readonly IContentRepository _repository;
private readonly ILogger<ContentQueryService> _logger;
public ContentQueryService(
IContentRepository repository,
ILogger<ContentQueryService> logger)
{
_repository = repository;
_logger = logger;
}
public async Task<IEnumerable<Article>> GetPublishedArticlesAsync()
{
return await _repository
.Query<Article>()
.Where(x => x.PublishDate.Value <= DateTime.UtcNow)
.OrderByDescending(x => x.PublishDate.Value)
.ToListAsync();
}
}