背景
ABP 中有文本模板模块,但是只提供了 scriban 的实现,且需要先定义模板名称、内容,操作起来不够简单。
需要利用 ABP 的文本模板模块,提供简单的调用方法,提供更多文本模板引擎,如 liquid。
具体来讲,需要为ITemplateRenderingEngine 接口及实现类添加一个新的方法,最外侧调用这个新的方法
思路
利用继承,
定义一个新的接口,继承原来的接口。
定义一个新的实现类,继承原来的实现类及新接口。如下
public interface IMyExtendedService : IOriginalService
{
void NewMethod();
}
public class MyExtendedService : OriginalServiceImplementation, IMyExtendedService
{
public void NewMethod()
{
// 实现新的方法
}
}
注意,module 类也要 DependOn 原来的类,如下
[DependsOn(
typeof(AbpTextTemplatingCoreModule)
)]
public class TextTemplatingCoreModule : AbpModule
{
}
有时,在 Module 中需要替换掉原来的实现类(因为新定义了接口和实现类)
[DependsOn(
typeof(TextTemplatingCoreModule),
typeof(AbpTextTemplatingScribanModule)
)]
public class TextTemplatingScribanModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpTextTemplatingOptions>(options =>
{
options.DefaultRenderingEngine = ScribanTemplateRenderingEngine.EngineName;
//覆盖掉默认的实现类ScribanTemplateRenderingEngine
options.RenderingEngines[ScribanTemplateRenderingEngine.EngineName] = typeof(ScribanCustomTemplateRenderingEngine);
});
}
}
具体代码
public interface ICustomTemplateRenderingEngine : ITemplateRenderingEngine, ITransientDependency
{
/// <summary>
/// 渲染一段模板体(新添加的方法)
/// </summary>
/// <param name="templateContent"></param>
/// <param name="model"></param>
/// <param name="cultureName"></param>
/// <param name="globalContext"></param>
/// <returns></returns>
Task<string> RenderTemplateAsync(
[NotNull] string templateContent,
object? model = null,
string? cultureName = null,
Dictionary<string, object>? globalContext = null
);
}
public abstract class CustomTemplateRenderingEngineBase : TemplateRenderingEngineBase, ICustomTemplateRenderingEngine
{
protected CustomTemplateRenderingEngineBase(ITemplateDefinitionManager templateDefinitionManager, ITemplateContentProvider templateContentProvider, IStringLocalizerFactory stringLocalizerFactory) : base(templateDefinitionManager, templateContentProvider, stringLocalizerFactory)
{
}
public abstract Task<string> RenderTemplateAsync([NotNull] string templatText, object? model = null, string? cultureName = null, Dictionary<string, object>? globalContext = null);
}
public class ScribanCustomTemplateRenderingEngine : ScribanTemplateRenderingEngine, ICustomTemplateRenderingEngine, ITransientDependency
{
public ScribanCustomTemplateRenderingEngine(ITemplateDefinitionManager templateDefinitionManager, ITemplateContentProvider templateContentProvider, IStringLocalizerFactory stringLocalizerFactory) : base(templateDefinitionManager, templateContentProvider, stringLocalizerFactory)
{
}
public async Task<string> RenderTemplateAsync([NotNull] string templateContent, object? model = null, string? cultureName = null, Dictionary<string, object>? globalContext = null)
{
//构造context
var context = new TemplateContext();
var scriptObject = new ScriptObject();
scriptObject.Import(globalContext);
//下面是字典对象的写法
if (model != null && model is IDictionary<string, object> dictionary)
{
scriptObject.Import(model);
//foreach (var kvp in dictionary)
//{
// scriptObject[kvp.Key] = kvp.Value;
//}
}
context.PushGlobal(scriptObject);
//渲染
return await Template
.Parse(templateContent)
.RenderAsync(context);
}
}
相关知识
替换服务注册
替换服务注册,就是替换实现类
[DependsOn(
typeof(OriginalAbpModule)
)]
public class MyCustomModule : AbpModule
{
public override void PreInitialize()
{
// 替换服务实现
Configuration.ReplaceService<IOriginalService, MyExtendedService>(DependencyLifeStyle.Transient);
}
}
装饰器模式
使用装饰器模式,可以在调用原方法之前或者之后添加额外的行为
public class MyExtendedServiceDecorator : IOriginalService
{
private readonly IOriginalService _originalService;
public MyExtendedServiceDecorator(IOriginalService originalService)
{
_originalService = originalService;
}
public void OriginalMethod()
{
// 可以在调用原始方法前后添加自定义行为
_originalService.OriginalMethod();
}
public void NewMethod()
{
// 新方法的实现
}
}