Skip to content

Commit 2d5145e

Browse files
committed
feat: 新增文本模板类型
1 parent 2afc0cb commit 2d5145e

29 files changed

+1154
-2
lines changed

Bing.All.sln

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bing.Logs.NLog", "framework
216216
EndProject
217217
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bing.Validation", "framework\src\Bing.Validation\Bing.Validation.csproj", "{D1131EC5-CF40-418F-8E8C-858AADDBCC7F}"
218218
EndProject
219-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bing.AspNetCore.Authentication.JwtBearer", "framework\src\Bing.AspNetCore.Authentication.JwtBearer\Bing.AspNetCore.Authentication.JwtBearer.csproj", "{7F4DAD82-FB09-445C-8EA2-0F1C50FBBA28}"
219+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bing.AspNetCore.Authentication.JwtBearer", "framework\src\Bing.AspNetCore.Authentication.JwtBearer\Bing.AspNetCore.Authentication.JwtBearer.csproj", "{7F4DAD82-FB09-445C-8EA2-0F1C50FBBA28}"
220+
EndProject
221+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TextTemplating", "TextTemplating", "{09A94120-CE45-402F-B45A-21DF04F0C226}"
222+
EndProject
223+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bing.TextTemplating", "framework\src\Bing.TextTemplating\Bing.TextTemplating.csproj", "{E06DC786-72AB-417B-ACDB-AF00688544EA}"
224+
EndProject
225+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bing.TextTemplating.Scriban", "framework\src\Bing.TextTemplating.Scriban\Bing.TextTemplating.Scriban.csproj", "{65B439C9-4B54-4DB8-86B3-9EBE8E62DF83}"
220226
EndProject
221227
Global
222228
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -484,6 +490,14 @@ Global
484490
{7F4DAD82-FB09-445C-8EA2-0F1C50FBBA28}.Debug|Any CPU.Build.0 = Debug|Any CPU
485491
{7F4DAD82-FB09-445C-8EA2-0F1C50FBBA28}.Release|Any CPU.ActiveCfg = Release|Any CPU
486492
{7F4DAD82-FB09-445C-8EA2-0F1C50FBBA28}.Release|Any CPU.Build.0 = Release|Any CPU
493+
{E06DC786-72AB-417B-ACDB-AF00688544EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
494+
{E06DC786-72AB-417B-ACDB-AF00688544EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
495+
{E06DC786-72AB-417B-ACDB-AF00688544EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
496+
{E06DC786-72AB-417B-ACDB-AF00688544EA}.Release|Any CPU.Build.0 = Release|Any CPU
497+
{65B439C9-4B54-4DB8-86B3-9EBE8E62DF83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
498+
{65B439C9-4B54-4DB8-86B3-9EBE8E62DF83}.Debug|Any CPU.Build.0 = Debug|Any CPU
499+
{65B439C9-4B54-4DB8-86B3-9EBE8E62DF83}.Release|Any CPU.ActiveCfg = Release|Any CPU
500+
{65B439C9-4B54-4DB8-86B3-9EBE8E62DF83}.Release|Any CPU.Build.0 = Release|Any CPU
487501
EndGlobalSection
488502
GlobalSection(SolutionProperties) = preSolution
489503
HideSolutionNode = FALSE
@@ -579,6 +593,9 @@ Global
579593
{A073A8B8-C116-4D8E-A519-DF950F68D2DA} = {33F6CAB3-FD8A-4B91-9B94-A1E2DBC2759B}
580594
{D1131EC5-CF40-418F-8E8C-858AADDBCC7F} = {C6B2743E-B7EE-418C-9F9B-79976B71C46B}
581595
{7F4DAD82-FB09-445C-8EA2-0F1C50FBBA28} = {052D4342-8B65-4836-A9B6-681A7812760E}
596+
{09A94120-CE45-402F-B45A-21DF04F0C226} = {3030FE3D-DB8F-403D-A181-8152670827AB}
597+
{E06DC786-72AB-417B-ACDB-AF00688544EA} = {09A94120-CE45-402F-B45A-21DF04F0C226}
598+
{65B439C9-4B54-4DB8-86B3-9EBE8E62DF83} = {09A94120-CE45-402F-B45A-21DF04F0C226}
582599
EndGlobalSection
583600
GlobalSection(ExtensibilityGlobals) = postSolution
584601
SolutionGuid = {C1202A0F-83CC-4602-BCE5-20CB640BCAD4}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<Import Project="project.props" />
3+
4+
<Import Project="project.dependency.props" />
5+
6+
<Import Project="..\..\..\framework.props" />
7+
8+
</Project>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
namespace Bing.TextTemplating.Scriban
2+
{
3+
/// <summary>
4+
/// Scriban模板定义扩展
5+
/// </summary>
6+
public static class ScribanTemplateDefinitionExtensions
7+
{
8+
/// <summary>
9+
/// 设置Scriban引擎
10+
/// </summary>
11+
/// <param name="templateDefinition">模板定义</param>
12+
public static TemplateDefinition WithScribanEngine(this TemplateDefinition templateDefinition) => templateDefinition.WithRenderEngine(ScribanTemplateRenderingEngine.EngineName);
13+
}
14+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
using System.Collections.Generic;
2+
using System.Globalization;
3+
using System.Threading.Tasks;
4+
using Bing.DependencyInjection;
5+
using Bing.Helpers;
6+
using Scriban;
7+
using Scriban.Runtime;
8+
9+
namespace Bing.TextTemplating.Scriban
10+
{
11+
/// <summary>
12+
/// Scriban模板渲染引擎
13+
/// </summary>
14+
public class ScribanTemplateRenderingEngine : TemplateRenderingEngineBase, ITransientDependency
15+
{
16+
/// <summary>
17+
/// 引擎名称
18+
/// </summary>
19+
public const string EngineName = "Scriban";
20+
21+
/// <summary>
22+
/// 名称
23+
/// </summary>
24+
public override string Name => EngineName;
25+
26+
/// <summary>
27+
/// 初始化一个<see cref="ScribanTemplateRenderingEngine"/>类型的实例
28+
/// </summary>
29+
/// <param name="templateDefinitionManager">模板定义管理器</param>
30+
/// <param name="templateContentProvider">模板内容提供程序</param>
31+
public ScribanTemplateRenderingEngine(
32+
ITemplateDefinitionManager templateDefinitionManager,
33+
ITemplateContentProvider templateContentProvider)
34+
: base(templateDefinitionManager, templateContentProvider)
35+
{
36+
}
37+
38+
/// <summary>
39+
/// 渲染
40+
/// </summary>
41+
/// <param name="templateName">模板名称</param>
42+
/// <param name="model">模型</param>
43+
/// <param name="cultureName">区域性名称</param>
44+
/// <param name="globalContext">全局上下文</param>
45+
public override async Task<string> RenderAsync(string templateName, object model = null, string cultureName = null, Dictionary<string, object> globalContext = null)
46+
{
47+
Check.NotNullOrEmpty(templateName, nameof(templateName));
48+
globalContext ??= new Dictionary<string, object>();
49+
return await RenderInternalAsync(templateName, globalContext, model);
50+
}
51+
52+
/// <summary>
53+
/// 内部渲染
54+
/// </summary>
55+
/// <param name="templateName">模板名称</param>
56+
/// <param name="globalContext">全局上下文</param>
57+
/// <param name="model">模型</param>
58+
protected virtual async Task<string> RenderInternalAsync(string templateName, Dictionary<string, object> globalContext, object model = null)
59+
{
60+
var templateDefinition = TemplateDefinitionManager.Get(templateName);
61+
var renderedContent = await RenderSingleTemplateAsync(templateDefinition, globalContext, model);
62+
if (templateDefinition.Layout != null)
63+
{
64+
globalContext["context"] = renderedContent;
65+
renderedContent = await RenderInternalAsync(templateDefinition.Layout, globalContext);
66+
}
67+
68+
return renderedContent;
69+
}
70+
71+
/// <summary>
72+
/// 渲染单个模板
73+
/// </summary>
74+
/// <param name="templateDefinition">模板定义</param>
75+
/// <param name="globalContext">全局上下文</param>
76+
/// <param name="model">模型</param>
77+
protected virtual async Task<string> RenderSingleTemplateAsync(TemplateDefinition templateDefinition, Dictionary<string, object> globalContext, object model = null)
78+
{
79+
var rawTemplateContent = await GetContentOrNullAsync(templateDefinition);
80+
return await RenderTemplateContentWithScribanAsync(templateDefinition, rawTemplateContent, globalContext, model);
81+
}
82+
83+
/// <summary>
84+
/// 渲染模板内容
85+
/// </summary>
86+
/// <param name="templateDefinition">模板定义</param>
87+
/// <param name="templateContent">模板内容</param>
88+
/// <param name="globalContext">全局上下文</param>
89+
/// <param name="model">模型</param>
90+
protected virtual async Task<string> RenderTemplateContentWithScribanAsync(TemplateDefinition templateDefinition, string templateContent, Dictionary<string, object> globalContext, object model = null)
91+
{
92+
var context = CreateScribanTemplateContext(templateDefinition, globalContext, model);
93+
return await Template.Parse(templateContent).RenderAsync(context);
94+
}
95+
96+
/// <summary>
97+
/// 创建Scriban模板上下文
98+
/// </summary>
99+
/// <param name="templateDefinition">模板定义</param>
100+
/// <param name="globalContext">全局上下文</param>
101+
/// <param name="model">模型</param>
102+
protected virtual TemplateContext CreateScribanTemplateContext(TemplateDefinition templateDefinition, Dictionary<string, object> globalContext, object model = null)
103+
{
104+
var context = new TemplateContext();
105+
var scriptObject = new ScriptObject();
106+
scriptObject.Import(globalContext);
107+
if (model != null)
108+
scriptObject["model"] = model;
109+
context.PushGlobal(scriptObject);
110+
context.PushCulture(CultureInfo.CurrentUICulture);
111+
return context;
112+
}
113+
}
114+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<Project>
2+
<ItemGroup>
3+
<ProjectReference Include="..\Bing.TextTemplating\Bing.TextTemplating.csproj" />
4+
</ItemGroup>
5+
6+
<ItemGroup>
7+
<PackageReference Include="Scriban" Version="4.0.2" />
8+
</ItemGroup>
9+
</Project>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<Project>
2+
<PropertyGroup>
3+
<AssemblyName>Bing.TextTemplating.Scriban</AssemblyName>
4+
<PackageId>Bing.TextTemplating.Scriban</PackageId>
5+
<Description>Bing.TextTemplating.Scriban是基于Scriban实现文本模板操作类库。</Description>
6+
</PropertyGroup>
7+
</Project>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<Import Project="project.props" />
3+
4+
<Import Project="project.dependency.props" />
5+
6+
<Import Project="..\..\..\framework.props" />
7+
8+
</Project>
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using System.Collections.Generic;
2+
using System.Threading.Tasks;
3+
using Bing.Collections;
4+
using Bing.DependencyInjection;
5+
using Bing.Exceptions;
6+
using Bing.Text;
7+
using Microsoft.Extensions.DependencyInjection;
8+
using Microsoft.Extensions.Options;
9+
10+
namespace Bing.TextTemplating
11+
{
12+
/// <summary>
13+
/// 模板渲染器
14+
/// </summary>
15+
public class BingTemplateRenderer : ITemplateRenderer, ITransientDependency
16+
{
17+
/// <summary>
18+
/// 服务作用域工厂
19+
/// </summary>
20+
protected IServiceScopeFactory ServiceScopeFactory { get; }
21+
22+
/// <summary>
23+
/// 模板定义管理器
24+
/// </summary>
25+
protected ITemplateDefinitionManager TemplateDefinitionManager { get; }
26+
27+
/// <summary>
28+
/// 文本模板选项配置
29+
/// </summary>
30+
protected BingTextTemplatingOptions Options { get; }
31+
32+
/// <summary>
33+
/// 初始化一个<see cref="BingTemplateRenderer"/>类型的实例
34+
/// </summary>
35+
/// <param name="serviceScopeFactory">服务作用域工厂</param>
36+
/// <param name="templateDefinitionManager">模板定义管理器</param>
37+
/// <param name="options">文本模板选项配置</param>
38+
public BingTemplateRenderer(
39+
IServiceScopeFactory serviceScopeFactory,
40+
ITemplateDefinitionManager templateDefinitionManager,
41+
IOptions<BingTextTemplatingOptions> options)
42+
{
43+
ServiceScopeFactory = serviceScopeFactory;
44+
TemplateDefinitionManager = templateDefinitionManager;
45+
Options = options.Value;
46+
}
47+
48+
/// <summary>
49+
/// 渲染
50+
/// </summary>
51+
/// <param name="templateName">模板名称</param>
52+
/// <param name="model">模型</param>
53+
/// <param name="cultureName">区域性名称</param>
54+
/// <param name="globalContext">全局上下文</param>
55+
public virtual async Task<string> RenderAsync(string templateName, object model = null, string cultureName = null, Dictionary<string, object> globalContext = null)
56+
{
57+
var templateDefinition = TemplateDefinitionManager.Get(templateName);
58+
var renderEngine = templateDefinition.RenderEngine;
59+
if (renderEngine.IsNullOrWhiteSpace())
60+
renderEngine = Options.DefaultRenderingEngine;
61+
var providerType = Options.RenderingEngines.GetOrDefault(renderEngine);
62+
if (providerType != null && typeof(ITemplateRenderingEngine).IsAssignableFrom(providerType))
63+
{
64+
using var scope = ServiceScopeFactory.CreateScope();
65+
var templateRenderingEngine = (ITemplateRenderingEngine)scope.ServiceProvider.GetRequiredService(providerType);
66+
return await templateRenderingEngine.RenderAsync(templateName, model, cultureName, globalContext);
67+
}
68+
throw new Warning("There is no rendering engine found with template name: " + templateName);
69+
}
70+
}
71+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Bing.Collections;
4+
5+
namespace Bing.TextTemplating
6+
{
7+
/// <summary>
8+
/// 文本模板选项配置
9+
/// </summary>
10+
public class BingTextTemplatingOptions
11+
{
12+
/// <summary>
13+
/// 模板定义提供程序 类型列表
14+
/// </summary>
15+
public ITypeList<ITemplateDefinitionProvider> DefinitionProviders { get; }
16+
17+
/// <summary>
18+
/// 模板内容构造者 类型列表
19+
/// </summary>
20+
public ITypeList<ITemplateContentContributor> ContentContributors { get; }
21+
22+
/// <summary>
23+
/// 渲染引擎字典
24+
/// </summary>
25+
public IDictionary<string, Type> RenderingEngines { get; }
26+
27+
/// <summary>
28+
/// 默认渲染引擎
29+
/// </summary>
30+
public string DefaultRenderingEngine { get; set; }
31+
32+
/// <summary>
33+
/// 初始化一个<see cref="BingTextTemplatingOptions"/>类型的实例
34+
/// </summary>
35+
public BingTextTemplatingOptions()
36+
{
37+
DefinitionProviders = new TypeList<ITemplateDefinitionProvider>();
38+
ContentContributors = new TypeList<ITemplateContentContributor>();
39+
RenderingEngines = new Dictionary<string, Type>();
40+
}
41+
}
42+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System.Threading.Tasks;
2+
3+
namespace Bing.TextTemplating
4+
{
5+
/// <summary>
6+
/// 模板内容构造者
7+
/// </summary>
8+
public interface ITemplateContentContributor
9+
{
10+
/// <summary>
11+
/// 获取模板内容
12+
/// </summary>
13+
/// <param name="context">模板内容构造者上下文</param>
14+
Task<string> GetOrNullAsync(TemplateContentContributorContext context);
15+
}
16+
}

0 commit comments

Comments
 (0)