diff --git a/framework/Volo.Abp.sln b/framework/Volo.Abp.sln index 67d2fa2573..b3af9241c4 100644 --- a/framework/Volo.Abp.sln +++ b/framework/Volo.Abp.sln @@ -383,6 +383,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Compone EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Mvc.UI.Bundling.Abstractions", "src\Volo.Abp.AspNetCore.Mvc.UI.Bundling.Abstractions\Volo.Abp.AspNetCore.Mvc.UI.Bundling.Abstractions.csproj", "{E9CE58DB-0789-4D18-8B63-474F7D7B14B4}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.TextTemplating.Abstractions", "src\Volo.Abp.TextTemplating.Abstractions\Volo.Abp.TextTemplating.Abstractions.csproj", "{184E859A-282D-44D7-B8E9-FEA874644013}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.TextTemplating.Scriban", "src\Volo.Abp.TextTemplating.Scriban\Volo.Abp.TextTemplating.Scriban.csproj", "{228723E6-FA6D-406B-B8F8-C9BCC547AF8E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.TextTemplating.Razor", "src\Volo.Abp.TextTemplating.Razor\Volo.Abp.TextTemplating.Razor.csproj", "{42EA6F06-2D78-4D18-8AC4-8F2AB7E6DA19}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.TextTemplating.Razor.Tests", "test\Volo.Abp.TextTemplating.Razor.Tests\Volo.Abp.TextTemplating.Razor.Tests.csproj", "{C996F458-98FB-483D-9306-4701290E2FC1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.TextTemplating.Scriban.Tests", "test\Volo.Abp.TextTemplating.Scriban.Tests\Volo.Abp.TextTemplating.Scriban.Tests.csproj", "{75D8DADB-3FA9-4C1D-B23A-DBFD08133B7C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1141,6 +1151,26 @@ Global {E9CE58DB-0789-4D18-8B63-474F7D7B14B4}.Debug|Any CPU.Build.0 = Debug|Any CPU {E9CE58DB-0789-4D18-8B63-474F7D7B14B4}.Release|Any CPU.ActiveCfg = Release|Any CPU {E9CE58DB-0789-4D18-8B63-474F7D7B14B4}.Release|Any CPU.Build.0 = Release|Any CPU + {184E859A-282D-44D7-B8E9-FEA874644013}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {184E859A-282D-44D7-B8E9-FEA874644013}.Debug|Any CPU.Build.0 = Debug|Any CPU + {184E859A-282D-44D7-B8E9-FEA874644013}.Release|Any CPU.ActiveCfg = Release|Any CPU + {184E859A-282D-44D7-B8E9-FEA874644013}.Release|Any CPU.Build.0 = Release|Any CPU + {228723E6-FA6D-406B-B8F8-C9BCC547AF8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {228723E6-FA6D-406B-B8F8-C9BCC547AF8E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {228723E6-FA6D-406B-B8F8-C9BCC547AF8E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {228723E6-FA6D-406B-B8F8-C9BCC547AF8E}.Release|Any CPU.Build.0 = Release|Any CPU + {42EA6F06-2D78-4D18-8AC4-8F2AB7E6DA19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {42EA6F06-2D78-4D18-8AC4-8F2AB7E6DA19}.Debug|Any CPU.Build.0 = Debug|Any CPU + {42EA6F06-2D78-4D18-8AC4-8F2AB7E6DA19}.Release|Any CPU.ActiveCfg = Release|Any CPU + {42EA6F06-2D78-4D18-8AC4-8F2AB7E6DA19}.Release|Any CPU.Build.0 = Release|Any CPU + {C996F458-98FB-483D-9306-4701290E2FC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C996F458-98FB-483D-9306-4701290E2FC1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C996F458-98FB-483D-9306-4701290E2FC1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C996F458-98FB-483D-9306-4701290E2FC1}.Release|Any CPU.Build.0 = Release|Any CPU + {75D8DADB-3FA9-4C1D-B23A-DBFD08133B7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {75D8DADB-3FA9-4C1D-B23A-DBFD08133B7C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {75D8DADB-3FA9-4C1D-B23A-DBFD08133B7C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {75D8DADB-3FA9-4C1D-B23A-DBFD08133B7C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1334,6 +1364,11 @@ Global {863C18F9-2407-49F9-9ADC-F6229AF3B385} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {B4B6B7DE-9798-4007-B1DF-7EE7929E392A} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {E9CE58DB-0789-4D18-8B63-474F7D7B14B4} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {184E859A-282D-44D7-B8E9-FEA874644013} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {228723E6-FA6D-406B-B8F8-C9BCC547AF8E} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {42EA6F06-2D78-4D18-8AC4-8F2AB7E6DA19} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {C996F458-98FB-483D-9306-4701290E2FC1} = {447C8A77-E5F0-4538-8687-7383196D04EA} + {75D8DADB-3FA9-4C1D-B23A-DBFD08133B7C} = {447C8A77-E5F0-4538-8687-7383196D04EA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5} diff --git a/framework/src/Volo.Abp.TextTemplating.Abstractions/FodyWeavers.xml b/framework/src/Volo.Abp.TextTemplating.Abstractions/FodyWeavers.xml new file mode 100644 index 0000000000..be0de3a908 --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Abstractions/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.TextTemplating.Abstractions/FodyWeavers.xsd b/framework/src/Volo.Abp.TextTemplating.Abstractions/FodyWeavers.xsd new file mode 100644 index 0000000000..3f3946e282 --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Abstractions/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo.Abp.TextTemplating.Abstractions.csproj b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo.Abp.TextTemplating.Abstractions.csproj new file mode 100644 index 0000000000..649bdc2912 --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo.Abp.TextTemplating.Abstractions.csproj @@ -0,0 +1,16 @@ + + + + + + + netstandard2.0 + + + + + + + + + diff --git a/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/AbpTextTemplatingAbstractionsModule.cs b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/AbpTextTemplatingAbstractionsModule.cs new file mode 100644 index 0000000000..bb76b299b2 --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/AbpTextTemplatingAbstractionsModule.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Localization; +using Volo.Abp.Modularity; +using Volo.Abp.VirtualFileSystem; + +namespace Volo.Abp.TextTemplating +{ + [DependsOn( + typeof(AbpVirtualFileSystemModule), + typeof(AbpLocalizationAbstractionsModule) + )] + public class AbpTextTemplatingAbstractionsModule : AbpModule + { + public override void PreConfigureServices(ServiceConfigurationContext context) + { + AutoAddProvidersAndContributors(context.Services); + } + + private static void AutoAddProvidersAndContributors(IServiceCollection services) + { + var definitionProviders = new List(); + var contentContributors = new List(); + + services.OnRegistred(context => + { + if (typeof(ITemplateDefinitionProvider).IsAssignableFrom(context.ImplementationType)) + { + definitionProviders.Add(context.ImplementationType); + } + + if (typeof(ITemplateContentContributor).IsAssignableFrom(context.ImplementationType)) + { + contentContributors.Add(context.ImplementationType); + } + }); + + services.Configure(options => + { + options.DefinitionProviders.AddIfNotContains(definitionProviders); + options.ContentContributors.AddIfNotContains(contentContributors); + }); + } + } +} diff --git a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/AbpTextTemplatingOptions.cs b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/AbpTextTemplatingOptions.cs similarity index 100% rename from framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/AbpTextTemplatingOptions.cs rename to framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/AbpTextTemplatingOptions.cs diff --git a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/ITemplateContentContributor.cs b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/ITemplateContentContributor.cs similarity index 100% rename from framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/ITemplateContentContributor.cs rename to framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/ITemplateContentContributor.cs diff --git a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/ITemplateContentProvider.cs b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/ITemplateContentProvider.cs similarity index 100% rename from framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/ITemplateContentProvider.cs rename to framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/ITemplateContentProvider.cs diff --git a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/ITemplateDefinitionContext.cs b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/ITemplateDefinitionContext.cs similarity index 100% rename from framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/ITemplateDefinitionContext.cs rename to framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/ITemplateDefinitionContext.cs diff --git a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/ITemplateDefinitionManager.cs b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/ITemplateDefinitionManager.cs similarity index 100% rename from framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/ITemplateDefinitionManager.cs rename to framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/ITemplateDefinitionManager.cs diff --git a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/ITemplateDefinitionProvider.cs b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/ITemplateDefinitionProvider.cs similarity index 100% rename from framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/ITemplateDefinitionProvider.cs rename to framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/ITemplateDefinitionProvider.cs diff --git a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/ITemplateRenderer.cs b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/ITemplateRenderer.cs similarity index 100% rename from framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/ITemplateRenderer.cs rename to framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/ITemplateRenderer.cs diff --git a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateContentContributorContext.cs b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateContentContributorContext.cs similarity index 100% rename from framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateContentContributorContext.cs rename to framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateContentContributorContext.cs diff --git a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateContentProvider.cs b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateContentProvider.cs similarity index 100% rename from framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateContentProvider.cs rename to framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateContentProvider.cs diff --git a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateDefinition.cs b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateDefinition.cs similarity index 100% rename from framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateDefinition.cs rename to framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateDefinition.cs diff --git a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateDefinitionContext.cs b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateDefinitionContext.cs similarity index 100% rename from framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateDefinitionContext.cs rename to framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateDefinitionContext.cs diff --git a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateDefinitionExtensions.cs b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateDefinitionExtensions.cs similarity index 100% rename from framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateDefinitionExtensions.cs rename to framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateDefinitionExtensions.cs diff --git a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateDefinitionManager.cs b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateDefinitionManager.cs similarity index 100% rename from framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateDefinitionManager.cs rename to framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateDefinitionManager.cs diff --git a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateDefinitionProvider.cs b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateDefinitionProvider.cs similarity index 100% rename from framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateDefinitionProvider.cs rename to framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateDefinitionProvider.cs diff --git a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/FileInfoLocalizedTemplateContentReader.cs b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/FileInfoLocalizedTemplateContentReader.cs similarity index 100% rename from framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/FileInfoLocalizedTemplateContentReader.cs rename to framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/FileInfoLocalizedTemplateContentReader.cs diff --git a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/ILocalizedTemplateContentReader.cs b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/ILocalizedTemplateContentReader.cs similarity index 100% rename from framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/ILocalizedTemplateContentReader.cs rename to framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/ILocalizedTemplateContentReader.cs diff --git a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/ILocalizedTemplateContentReaderFactory.cs b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/ILocalizedTemplateContentReaderFactory.cs similarity index 100% rename from framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/ILocalizedTemplateContentReaderFactory.cs rename to framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/ILocalizedTemplateContentReaderFactory.cs diff --git a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/LocalizedTemplateContentReaderFactory.cs b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/LocalizedTemplateContentReaderFactory.cs similarity index 96% rename from framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/LocalizedTemplateContentReaderFactory.cs rename to framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/LocalizedTemplateContentReaderFactory.cs index 981d1f8819..cc189e1b3b 100644 --- a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/LocalizedTemplateContentReaderFactory.cs +++ b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/LocalizedTemplateContentReaderFactory.cs @@ -64,7 +64,8 @@ namespace Volo.Abp.TextTemplating.VirtualFiles if (fileInfo.IsDirectory) { - var folderReader = new VirtualFolderLocalizedTemplateContentReader(); + //TODO: Configure file extensions. + var folderReader = new VirtualFolderLocalizedTemplateContentReader(new[] {".tpl", ".cshtml"}); await folderReader.ReadContentsAsync(VirtualFileProvider, virtualPath); return folderReader; } diff --git a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/NullLocalizedTemplateContentReader.cs b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/NullLocalizedTemplateContentReader.cs similarity index 100% rename from framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/NullLocalizedTemplateContentReader.cs rename to framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/NullLocalizedTemplateContentReader.cs diff --git a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/VirtualFileTemplateContentContributor.cs b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/VirtualFileTemplateContentContributor.cs similarity index 100% rename from framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/VirtualFileTemplateContentContributor.cs rename to framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/VirtualFileTemplateContentContributor.cs diff --git a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/VirtualFolderLocalizedTemplateContentReader.cs b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/VirtualFolderLocalizedTemplateContentReader.cs similarity index 80% rename from framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/VirtualFolderLocalizedTemplateContentReader.cs rename to framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/VirtualFolderLocalizedTemplateContentReader.cs index 6fc7ff4847..27458d02cc 100644 --- a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/VirtualFolderLocalizedTemplateContentReader.cs +++ b/framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/VirtualFolderLocalizedTemplateContentReader.cs @@ -9,6 +9,12 @@ namespace Volo.Abp.TextTemplating.VirtualFiles public class VirtualFolderLocalizedTemplateContentReader : ILocalizedTemplateContentReader { private Dictionary _dictionary; + private readonly string[] _fileExtension; + + public VirtualFolderLocalizedTemplateContentReader(string[] fileExtension) + { + _fileExtension = fileExtension; + } public async Task ReadContentsAsync( IVirtualFileProvider virtualFileProvider, @@ -29,7 +35,7 @@ namespace Volo.Abp.TextTemplating.VirtualFiles continue; } - _dictionary.Add(file.Name.RemovePostFix(".tpl"), await file.ReadAsStringAsync()); + _dictionary.Add(file.Name.RemovePostFix(_fileExtension), await file.ReadAsStringAsync()); } } diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/FodyWeavers.xml b/framework/src/Volo.Abp.TextTemplating.Razor/FodyWeavers.xml new file mode 100644 index 0000000000..be0de3a908 --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Razor/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/FodyWeavers.xsd b/framework/src/Volo.Abp.TextTemplating.Razor/FodyWeavers.xsd new file mode 100644 index 0000000000..3f3946e282 --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Razor/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/Volo.Abp.TextTemplating.Razor.csproj b/framework/src/Volo.Abp.TextTemplating.Razor/Volo.Abp.TextTemplating.Razor.csproj new file mode 100644 index 0000000000..f4d16e630c --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo.Abp.TextTemplating.Razor.csproj @@ -0,0 +1,21 @@ + + + + + + + netstandard2.0 + + + + + + + + + + + + + + diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/AbpRazorTemplateConsts.cs b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/AbpRazorTemplateConsts.cs new file mode 100644 index 0000000000..7701a89630 --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/AbpRazorTemplateConsts.cs @@ -0,0 +1,9 @@ +namespace Volo.Abp.TextTemplating.Razor +{ + public static class AbpRazorTemplateConsts + { + public const string DefaultNameSpace = "Abp.Razor"; + public const string DefaultClassName = "Template"; + public const string TypeName = DefaultNameSpace + "." + DefaultClassName; + } +} diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/AbpTextTemplatingRazorModule.cs b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/AbpTextTemplatingRazorModule.cs new file mode 100644 index 0000000000..318a356b93 --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/AbpTextTemplatingRazorModule.cs @@ -0,0 +1,12 @@ +using Volo.Abp.Modularity; + +namespace Volo.Abp.TextTemplating.Razor +{ + [DependsOn( + typeof(AbpTextTemplatingAbstractionsModule) + )] + public class AbpTextTemplatingRazorModule : AbpModule + { + + } +} diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/CSharpCompiler.cs b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/CSharpCompiler.cs new file mode 100644 index 0000000000..5c6bc2d190 --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/CSharpCompiler.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.TextTemplating.Razor +{ + public class CSharpCompiler : ISingletonDependency + { + protected CSharpCompilerOptions Options { get; } + + public CSharpCompiler(IOptions options) + { + Options = options.Value; + } + + private static IEnumerable DefaultReferences => new List() + { + Assembly.Load("netstandard"), + Assembly.Load("System.Private.CoreLib"), + Assembly.Load("System.Runtime"), + Assembly.Load("System.Collections"), + Assembly.Load("System.ComponentModel"), + Assembly.Load("System.Linq"), + Assembly.Load("System.Linq.Expressions"), + Assembly.Load("Microsoft.Extensions.DependencyInjection"), + Assembly.Load("Microsoft.Extensions.DependencyInjection.Abstractions"), + Assembly.Load("Microsoft.Extensions.Localization"), + Assembly.Load("Microsoft.Extensions.Localization.Abstractions"), + + typeof(CSharpCompiler).Assembly + } + .Select(x => MetadataReference.CreateFromFile(x.Location)) + .ToImmutableList(); + + public virtual Stream CreateAssembly(string code, string assemblyName, List references = null, CSharpCompilationOptions options = null) + { + var defaultReferences = DefaultReferences.Concat(Options.References); + try + { + var compilation = CSharpCompilation.Create( + assemblyName, + syntaxTrees: new[] { CreateSyntaxTree(code) }, + references: references != null ? defaultReferences.Concat(references) : defaultReferences, + options ?? GetCompilationOptions()); + + using (var memoryStream = new MemoryStream()) + { + var result = compilation.Emit(memoryStream); + + if (!result.Success) + { + var error = new StringBuilder(); + error.AppendLine("Build failed"); + foreach (var diagnostic in result.Diagnostics) + { + error.AppendLine(diagnostic.ToString()); + } + + throw new Exception(error.ToString()); + } + + memoryStream.Seek(0, SeekOrigin.Begin); + var assemblyStream = new MemoryStream(); + memoryStream.CopyTo(assemblyStream); + + return assemblyStream; + } + } + catch (Exception e) + { + var error = new StringBuilder(); + error.AppendLine("CreateAssembly failed"); + error.AppendLine(e.Message); + throw new Exception(error.ToString()); + } + } + + protected virtual SyntaxTree CreateSyntaxTree(string code) + { + return CSharpSyntaxTree.ParseText(code); + } + + protected virtual CSharpCompilationOptions GetCompilationOptions() + { + var csharpCompilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary); + + // Disable 1702 until roslyn turns this off by default + csharpCompilationOptions = csharpCompilationOptions.WithSpecificDiagnosticOptions( + new Dictionary + { + {"CS1701", ReportDiagnostic.Suppress}, // Binding redirects + {"CS1702", ReportDiagnostic.Suppress}, + {"CS1705", ReportDiagnostic.Suppress} + }); + + return csharpCompilationOptions.WithOptimizationLevel(OptimizationLevel.Release); + } + } +} diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/CSharpCompilerOptions.cs b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/CSharpCompilerOptions.cs new file mode 100644 index 0000000000..d419b83fca --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/CSharpCompilerOptions.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using Microsoft.CodeAnalysis; + +namespace Volo.Abp.TextTemplating.Razor +{ + public class CSharpCompilerOptions + { + public List References { get; } + + public CSharpCompilerOptions() + { + References = new List(); + } + } +} diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultCompiledViewProvider.cs b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultCompiledViewProvider.cs new file mode 100644 index 0000000000..ff954b3b99 --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultCompiledViewProvider.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Language; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.TextTemplating.Razor +{ + public class DefaultCompiledViewProvider : ICompiledViewProvider, ITransientDependency + { + private static readonly ConcurrentDictionary CachedAssembles = new ConcurrentDictionary(); + + private readonly CSharpCompiler _cSharpCompiler; + private readonly IRazorProjectEngineFactory _razorProjectEngineFactory; + private readonly ITemplateContentProvider _templateContentProvider; + + public DefaultCompiledViewProvider( + IRazorProjectEngineFactory razorProjectEngineFactory, + CSharpCompiler cSharpCompiler, + ITemplateContentProvider templateContentProvider) + { + _razorProjectEngineFactory = razorProjectEngineFactory; + _cSharpCompiler = cSharpCompiler; + _templateContentProvider = templateContentProvider; + } + + public virtual async Task GetAssemblyAsync(TemplateDefinition templateDefinition) + { + async Task CreateAssembly(string content) + { + using (var assemblyStream = await GetAssemblyStreamAsync(templateDefinition, content)) + { + return Assembly.Load(await assemblyStream.GetAllBytesAsync()); + } + } + + var templateContent = await _templateContentProvider.GetContentOrNullAsync(templateDefinition); + return CachedAssembles.GetOrAdd((templateDefinition.Name + templateContent).ToMd5(), await CreateAssembly(templateContent)); + } + + protected virtual async Task GetAssemblyStreamAsync(TemplateDefinition templateDefinition, string templateContent) + { + var razorProjectEngine = await _razorProjectEngineFactory.CreateAsync(builder => + { + builder.SetNamespace(AbpRazorTemplateConsts.DefaultNameSpace); + builder.ConfigureClass((document, node) => + { + node.ClassName = AbpRazorTemplateConsts.DefaultClassName; + }); + }); + + var codeDocument = razorProjectEngine.Process( + RazorSourceDocument.Create(templateContent, templateDefinition.Name), null, + new List(), new List()); + + var cSharpDocument = codeDocument.GetCSharpDocument(); + + return _cSharpCompiler.CreateAssembly(cSharpDocument.GeneratedCode, templateDefinition.Name); + } + } +} diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultRazorProjectEngineFactory.cs b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultRazorProjectEngineFactory.cs new file mode 100644 index 0000000000..c402a26bb2 --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultRazorProjectEngineFactory.cs @@ -0,0 +1,20 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Language; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.TextTemplating.Razor +{ + public class DefaultRazorProjectEngineFactory : IRazorProjectEngineFactory, ITransientDependency + { + public virtual async Task CreateAsync(Action configure = null) + { + return RazorProjectEngine.Create(await CreateRazorConfigurationAsync(), EmptyProjectFileSystem.Empty, configure); + } + + protected virtual Task CreateRazorConfigurationAsync() + { + return Task.FromResult(RazorConfiguration.Default); + } + } +} diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/EmptyProjectFileSystem.cs b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/EmptyProjectFileSystem.cs new file mode 100644 index 0000000000..496e86e977 --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/EmptyProjectFileSystem.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Razor.Language; + +namespace Volo.Abp.TextTemplating.Razor +{ + internal class EmptyProjectFileSystem : RazorProjectFileSystem + { + internal static readonly RazorProjectFileSystem Empty = new EmptyProjectFileSystem(); + + public override IEnumerable EnumerateItems(string basePath) + { + NormalizeAndEnsureValidPath(basePath); + return Enumerable.Empty(); + } + + [Obsolete("Use GetItem(string path, string fileKind) instead.")] + public override RazorProjectItem GetItem(string path) + { + return GetItem(path, fileKind: null); + } + + public override RazorProjectItem GetItem(string path, string fileKind) + { + NormalizeAndEnsureValidPath(path); + return new NotFoundProjectItem(string.Empty, path, fileKind); + } + } +} diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/ICompiledViewProvider.cs b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/ICompiledViewProvider.cs new file mode 100644 index 0000000000..a0bc2043aa --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/ICompiledViewProvider.cs @@ -0,0 +1,10 @@ +using System.Reflection; +using System.Threading.Tasks; + +namespace Volo.Abp.TextTemplating.Razor +{ + public interface ICompiledViewProvider + { + Task GetAssemblyAsync(TemplateDefinition templateDefinition); + } +} diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/IRazorProjectEngineFactory.cs b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/IRazorProjectEngineFactory.cs new file mode 100644 index 0000000000..138a78b72f --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/IRazorProjectEngineFactory.cs @@ -0,0 +1,11 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Language; + +namespace Volo.Abp.TextTemplating.Razor +{ + public interface IRazorProjectEngineFactory + { + Task CreateAsync(Action configure = null); + } +} diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/IRazorTemplatePage.cs b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/IRazorTemplatePage.cs new file mode 100644 index 0000000000..fc386c3353 --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/IRazorTemplatePage.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using Microsoft.Extensions.Localization; + +namespace Volo.Abp.TextTemplating.Razor +{ + public interface IRazorTemplatePage : IRazorTemplatePage + { + TModel Model { get; set; } + } + + public interface IRazorTemplatePage + { + IServiceProvider ServiceProvider { get; set; } + + IStringLocalizer Localizer { get; set; } + + HtmlEncoder HtmlEncoder { get; set; } + + JavaScriptEncoder JavaScriptEncoder { get; set; } + + UrlEncoder UrlEncoder { get; set; } + + Dictionary GlobalContext { get; set; } + + string Body { get; set; } + + Task ExecuteAsync(); + + Task GetOutputAsync(); + } +} diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/NotFoundProjectItem.cs b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/NotFoundProjectItem.cs new file mode 100644 index 0000000000..735522bd09 --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/NotFoundProjectItem.cs @@ -0,0 +1,28 @@ +using System; +using System.IO; +using Microsoft.AspNetCore.Razor.Language; + +namespace Volo.Abp.TextTemplating.Razor +{ + internal class NotFoundProjectItem : RazorProjectItem + { + public NotFoundProjectItem(string basePath, string path, string fileKind) + { + BasePath = basePath; + FilePath = path; + FileKind = fileKind ?? FileKinds.GetFileKindFromFilePath(path); + } + + public override string BasePath { get; } + + public override string FilePath { get; } + + public override string FileKind { get; } + + public override bool Exists => false; + + public override string PhysicalPath => throw new NotSupportedException(); + + public override Stream Read() => throw new NotSupportedException(); + } +} diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/RazorTemplatePageBase.cs b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/RazorTemplatePageBase.cs new file mode 100644 index 0000000000..9854775a25 --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/RazorTemplatePageBase.cs @@ -0,0 +1,177 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using Microsoft.Extensions.Localization; + +namespace Volo.Abp.TextTemplating.Razor +{ + public abstract class RazorTemplatePageBase : RazorTemplatePageBase, IRazorTemplatePage + { + public TModel Model { get; set; } + } + + public abstract class RazorTemplatePageBase : IRazorTemplatePage + { + public Dictionary GlobalContext { get; set; } + + public IServiceProvider ServiceProvider { get; set; } + + public IStringLocalizer Localizer { get; set; } + + public HtmlEncoder HtmlEncoder { get; set; } + + public JavaScriptEncoder JavaScriptEncoder { get; set; } + + public UrlEncoder UrlEncoder { get; set; } + + public string Body { get; set; } + + private readonly StringBuilder _stringBuilder = new StringBuilder(); + + private AttributeInfo _attributeInfo; + + public virtual void WriteLiteral(string literal = null) + { + _stringBuilder.Append(literal); + } + + public virtual void Write(object obj = null) + { + _stringBuilder.Append(obj); + } + + public virtual void BeginWriteAttribute(string name, string prefix, int prefixOffset, string suffix, int suffixOffset, int attributeValuesCount) + { + _attributeInfo = new AttributeInfo(name, prefix, prefixOffset, suffix, suffixOffset, attributeValuesCount); + WriteLiteral(prefix); + } + + public virtual void WriteAttributeValue(string prefix, int prefixOffset, object value, int valueOffset, int valueLength, bool isLiteral) + { + if (_attributeInfo.AttributeValuesCount == 1) + { + if (IsBoolFalseOrNullValue(prefix, value)) + { + // Value is either null or the bool 'false' with no prefix; don't render the attribute. + _attributeInfo.Suppressed = true; + return; + } + + // We are not omitting the attribute. Write the prefix. + WriteLiteral(_attributeInfo.Prefix); + + if (IsBoolTrueWithEmptyPrefixValue(prefix, value)) + { + // The value is just the bool 'true', write the attribute name instead of the string 'True'. + value = _attributeInfo.Name; + } + } + + // This block handles two cases. + // 1. Single value with prefix. + // 2. Multiple values with or without prefix. + if (value != null) + { + if (!string.IsNullOrEmpty(prefix)) + { + WriteLiteral(prefix); + } + + WriteUnprefixedAttributeValue(value, isLiteral); + } + + _stringBuilder.Append(prefix); + _stringBuilder.Append(value); + } + + public virtual void EndWriteAttribute() + { + if (!_attributeInfo.Suppressed) + { + WriteLiteral(_attributeInfo.Suffix); + } + } + + public virtual Task ExecuteAsync() + { + return Task.CompletedTask; + } + + public virtual Task GetOutputAsync() + { + return Task.FromResult(_stringBuilder.ToString()); + } + + private void WriteUnprefixedAttributeValue(object value, bool isLiteral) + { + var stringValue = value as string; + + // The extra branching here is to ensure that we call the Write*To(string) overload where possible. + if (isLiteral && stringValue != null) + { + WriteLiteral(stringValue); + } + else if (isLiteral) + { + //WriteLiteral(value); + _stringBuilder.Append(value); + } + else if (stringValue != null) + { + Write(stringValue); + } + else + { + Write(value); + } + } + + private bool IsBoolFalseOrNullValue(string prefix, object value) + { + return string.IsNullOrEmpty(prefix) && (value == null || (value is bool b && !b)); + } + + private bool IsBoolTrueWithEmptyPrefixValue(string prefix, object value) + { + // If the value is just the bool 'true', use the attribute name as the value. + return string.IsNullOrEmpty(prefix) && (value is bool b && b); + } + + private struct AttributeInfo + { + public AttributeInfo( + string name, + string prefix, + int prefixOffset, + string suffix, + int suffixOffset, + int attributeValuesCount) + { + Name = name; + Prefix = prefix; + PrefixOffset = prefixOffset; + Suffix = suffix; + SuffixOffset = suffixOffset; + AttributeValuesCount = attributeValuesCount; + + Suppressed = false; + } + + public int AttributeValuesCount { get; } + + public string Name { get; } + + public string Prefix { get; } + + public int PrefixOffset { get; } + + public string Suffix { get; } + + public int SuffixOffset { get; } + + public bool Suppressed { get; set; } + } + } +} diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/RazorTemplateRenderer.cs b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/RazorTemplateRenderer.cs new file mode 100644 index 0000000000..6ec926b398 --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/RazorTemplateRenderer.cs @@ -0,0 +1,168 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using JetBrains.Annotations; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Localization; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Localization; + +namespace Volo.Abp.TextTemplating.Razor +{ + [Dependency(ReplaceServices = true)] + public class RazorTemplateRenderer : ITemplateRenderer, ITransientDependency + { + private readonly IServiceScopeFactory _serviceScopeFactory; + private readonly ICompiledViewProvider _compiledViewProvider; + private readonly ITemplateDefinitionManager _templateDefinitionManager; + private readonly IStringLocalizerFactory _stringLocalizerFactory; + + public RazorTemplateRenderer( + IServiceScopeFactory serviceScopeFactory, + ICompiledViewProvider compiledViewProvider, + ITemplateDefinitionManager templateDefinitionManager, + IStringLocalizerFactory stringLocalizerFactory) + { + _serviceScopeFactory = serviceScopeFactory; + _templateDefinitionManager = templateDefinitionManager; + _stringLocalizerFactory = stringLocalizerFactory; + _compiledViewProvider = compiledViewProvider; + } + + public virtual async Task RenderAsync( + [NotNull] string templateName, + [CanBeNull] object model = null, + [CanBeNull] string cultureName = null, + [CanBeNull] Dictionary globalContext = null) + { + Check.NotNullOrWhiteSpace(templateName, nameof(templateName)); + + if (globalContext == null) + { + globalContext = new Dictionary(); + } + + if (cultureName == null) + { + return await RenderInternalAsync( + templateName, + null, + globalContext, + model + ); + } + else + { + using (CultureHelper.Use(cultureName)) + { + return await RenderInternalAsync( + templateName, + null, + globalContext, + model + ); + } + } + } + + protected virtual async Task RenderInternalAsync( + string templateName, + string body, + Dictionary globalContext, + object model = null) + { + var templateDefinition = _templateDefinitionManager.Get(templateName); + + var renderedContent = await RenderSingleTemplateAsync( + templateDefinition, + body, + globalContext, + model + ); + + if (templateDefinition.Layout != null) + { + renderedContent = await RenderInternalAsync( + templateDefinition.Layout, + renderedContent, + globalContext + ); + } + + return renderedContent; + } + + protected virtual async Task RenderSingleTemplateAsync( + TemplateDefinition templateDefinition, + string body, + Dictionary globalContext, + object model = null) + { + return await RenderTemplateContentWithRazorAsync( + templateDefinition, + body, + globalContext, + model + ); + } + + protected virtual async Task RenderTemplateContentWithRazorAsync( + TemplateDefinition templateDefinition, + string body, + Dictionary globalContext, + object model = null) + { + var assembly = await _compiledViewProvider.GetAssemblyAsync(templateDefinition); + var templateType = assembly.GetType(AbpRazorTemplateConsts.TypeName); + var template = (IRazorTemplatePage) Activator.CreateInstance(templateType); + + using (var scope = _serviceScopeFactory.CreateScope()) + { + var modelType = templateType + .GetInterfaces() + .Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IRazorTemplatePage<>)) + .Select(x => x.GenericTypeArguments.FirstOrDefault()) + .FirstOrDefault(); + + if (modelType != null) + { + GetType().GetMethod(nameof(SetModel), BindingFlags.Instance | BindingFlags.NonPublic) + ?.MakeGenericMethod(modelType).Invoke(this, new[] {template, model}); + } + + template.ServiceProvider = scope.ServiceProvider; + template.Localizer = GetLocalizerOrNull(templateDefinition); + template.HtmlEncoder = scope.ServiceProvider.GetService(); + template.JavaScriptEncoder = scope.ServiceProvider.GetService(); + template.UrlEncoder = scope.ServiceProvider.GetService(); + template.Body = body; + template.GlobalContext = globalContext; + + await template.ExecuteAsync(); + + return await template.GetOutputAsync(); + } + } + + private void SetModel(IRazorTemplatePage razorTemplatePage, object model = null) + { + if (razorTemplatePage is IRazorTemplatePage razorTemplatePageWithModel) + { + razorTemplatePageWithModel.Model = (TModel)model; + } + } + + private IStringLocalizer GetLocalizerOrNull(TemplateDefinition templateDefinition) + { + if (templateDefinition.LocalizationResource != null) + { + return _stringLocalizerFactory.Create(templateDefinition.LocalizationResource); + } + + return _stringLocalizerFactory.CreateDefaultOrNull(); + } + } +} diff --git a/framework/src/Volo.Abp.TextTemplating.Scriban/FodyWeavers.xml b/framework/src/Volo.Abp.TextTemplating.Scriban/FodyWeavers.xml new file mode 100644 index 0000000000..be0de3a908 --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Scriban/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.TextTemplating.Scriban/FodyWeavers.xsd b/framework/src/Volo.Abp.TextTemplating.Scriban/FodyWeavers.xsd new file mode 100644 index 0000000000..3f3946e282 --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Scriban/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.TextTemplating.Scriban/Volo.Abp.TextTemplating.Scriban.csproj b/framework/src/Volo.Abp.TextTemplating.Scriban/Volo.Abp.TextTemplating.Scriban.csproj new file mode 100644 index 0000000000..b4b0d66789 --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Scriban/Volo.Abp.TextTemplating.Scriban.csproj @@ -0,0 +1,19 @@ + + + + + + + netstandard2.0 + + + + + + + + + + + + diff --git a/framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/AbpTextTemplatingScribanModule.cs b/framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/AbpTextTemplatingScribanModule.cs new file mode 100644 index 0000000000..789b9e376f --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/AbpTextTemplatingScribanModule.cs @@ -0,0 +1,12 @@ +using Volo.Abp.Modularity; + +namespace Volo.Abp.TextTemplating.Scriban +{ + [DependsOn( + typeof(AbpTextTemplatingAbstractionsModule) + )] + public class AbpTextTemplatingScribanModule : AbpModule + { + + } +} diff --git a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateLocalizer.cs b/framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/ScribanTemplateLocalizer.cs similarity index 91% rename from framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateLocalizer.cs rename to framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/ScribanTemplateLocalizer.cs index 4e4a1e4833..e280cd194a 100644 --- a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateLocalizer.cs +++ b/framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/ScribanTemplateLocalizer.cs @@ -7,13 +7,13 @@ using Scriban; using Scriban.Runtime; using Scriban.Syntax; -namespace Volo.Abp.TextTemplating +namespace Volo.Abp.TextTemplating.Scriban { - public class TemplateLocalizer : IScriptCustomFunction + public class ScribanTemplateLocalizer : IScriptCustomFunction { private readonly IStringLocalizer _localizer; - public TemplateLocalizer(IStringLocalizer localizer) + public ScribanTemplateLocalizer(IStringLocalizer localizer) { _localizer = localizer; } diff --git a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateRenderer.cs b/framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/ScribanTemplateRenderer.cs similarity index 94% rename from framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateRenderer.cs rename to framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/ScribanTemplateRenderer.cs index 1d89dc3b68..3fdd667a82 100644 --- a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateRenderer.cs +++ b/framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/ScribanTemplateRenderer.cs @@ -1,23 +1,21 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; using JetBrains.Annotations; using Microsoft.Extensions.Localization; -using Microsoft.Extensions.Options; using Scriban; using Scriban.Runtime; using Volo.Abp.DependencyInjection; using Volo.Abp.Localization; -namespace Volo.Abp.TextTemplating +namespace Volo.Abp.TextTemplating.Scriban { - public class TemplateRenderer : ITemplateRenderer, ITransientDependency + public class ScribanTemplateRenderer : ITemplateRenderer, ITransientDependency { private readonly ITemplateContentProvider _templateContentProvider; private readonly ITemplateDefinitionManager _templateDefinitionManager; private readonly IStringLocalizerFactory _stringLocalizerFactory; - public TemplateRenderer( + public ScribanTemplateRenderer( ITemplateContentProvider templateContentProvider, ITemplateDefinitionManager templateDefinitionManager, IStringLocalizerFactory stringLocalizerFactory) @@ -140,7 +138,7 @@ namespace Volo.Abp.TextTemplating var localizer = GetLocalizerOrNull(templateDefinition); if (localizer != null) { - scriptObject.SetValue("L", new TemplateLocalizer(localizer), true); + scriptObject.SetValue("L", new ScribanTemplateLocalizer(localizer), true); } context.PushGlobal(scriptObject); diff --git a/framework/src/Volo.Abp.TextTemplating/Volo.Abp.TextTemplating.csproj b/framework/src/Volo.Abp.TextTemplating/Volo.Abp.TextTemplating.csproj index 506b086a88..3af0ba984d 100644 --- a/framework/src/Volo.Abp.TextTemplating/Volo.Abp.TextTemplating.csproj +++ b/framework/src/Volo.Abp.TextTemplating/Volo.Abp.TextTemplating.csproj @@ -5,22 +5,11 @@ netstandard2.0 - Volo.Abp.TextTemplating - Volo.Abp.TextTemplating - $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; - false - false - false - - - - - - + diff --git a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/AbpTextTemplatingModule.cs b/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/AbpTextTemplatingModule.cs index 8d76391829..6b0ad6fb11 100644 --- a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/AbpTextTemplatingModule.cs +++ b/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/AbpTextTemplatingModule.cs @@ -1,46 +1,9 @@ -using System; -using System.Collections.Generic; -using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.Localization; -using Volo.Abp.Modularity; -using Volo.Abp.VirtualFileSystem; +using Volo.Abp.Modularity; namespace Volo.Abp.TextTemplating { - [DependsOn( - typeof(AbpVirtualFileSystemModule), - typeof(AbpLocalizationAbstractionsModule) - )] public class AbpTextTemplatingModule : AbpModule { - public override void PreConfigureServices(ServiceConfigurationContext context) - { - AutoAddProvidersAndContributors(context.Services); - } - private static void AutoAddProvidersAndContributors(IServiceCollection services) - { - var definitionProviders = new List(); - var contentContributors = new List(); - - services.OnRegistred(context => - { - if (typeof(ITemplateDefinitionProvider).IsAssignableFrom(context.ImplementationType)) - { - definitionProviders.Add(context.ImplementationType); - } - - if (typeof(ITemplateContentContributor).IsAssignableFrom(context.ImplementationType)) - { - contentContributors.Add(context.ImplementationType); - } - }); - - services.Configure(options => - { - options.DefinitionProviders.AddIfNotContains(definitionProviders); - options.ContentContributors.AddIfNotContains(contentContributors); - }); - } } } diff --git a/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo.Abp.TextTemplating.Razor.Tests.csproj b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo.Abp.TextTemplating.Razor.Tests.csproj new file mode 100644 index 0000000000..ca26b60a4b --- /dev/null +++ b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo.Abp.TextTemplating.Razor.Tests.csproj @@ -0,0 +1,23 @@ + + + + + + net5.0 + + + + + + Always + + + + + + + + + + + diff --git a/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorLocalizedTemplateContentReaderFactory_Tests.cs b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorLocalizedTemplateContentReaderFactory_Tests.cs new file mode 100644 index 0000000000..53eaf0fc80 --- /dev/null +++ b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorLocalizedTemplateContentReaderFactory_Tests.cs @@ -0,0 +1,26 @@ +using System; +using System.IO; +using Microsoft.Extensions.FileProviders; +using Volo.Abp.TextTemplating.VirtualFiles; + +namespace Volo.Abp.TextTemplating.Razor +{ + public class RazorLocalizedTemplateContentReaderFactory_Tests : LocalizedTemplateContentReaderFactory_Tests + { + public RazorLocalizedTemplateContentReaderFactory_Tests() + { + LocalizedTemplateContentReaderFactory = new LocalizedTemplateContentReaderFactory( + new PhysicalFileVirtualFileProvider( + new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), + "Volo", "Abp", "TextTemplating", "Razor")))); + + WelcomeEmailEnglishContent = "@inherits Volo.Abp.TextTemplating.Razor.RazorTemplatePageBase" + + Environment.NewLine + + "Welcome @Model.Name to the abp.io!"; + + WelcomeEmailTurkishContent = "@inherits Volo.Abp.TextTemplating.Razor.RazorTemplatePageBase" + + Environment.NewLine + + "Merhaba @Model.Name, abp.io'ya hoşgeldiniz!"; + } + } +} diff --git a/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorTemplateDefinitionTests.cs b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorTemplateDefinitionTests.cs new file mode 100644 index 0000000000..53c40b5ea8 --- /dev/null +++ b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorTemplateDefinitionTests.cs @@ -0,0 +1,7 @@ +namespace Volo.Abp.TextTemplating.Razor +{ + public class RazorTemplateDefinitionTests : TemplateDefinitionTests + { + + } +} diff --git a/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorTemplateRenderer_Tests.cs b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorTemplateRenderer_Tests.cs new file mode 100644 index 0000000000..07da572c1e --- /dev/null +++ b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorTemplateRenderer_Tests.cs @@ -0,0 +1,145 @@ +using System.Threading.Tasks; +using Shouldly; +using Xunit; + +namespace Volo.Abp.TextTemplating.Razor +{ + public class RazorTemplateRenderer_Tests : AbpTextTemplatingTestBase + { + private readonly ITemplateRenderer _templateRenderer; + + public RazorTemplateRenderer_Tests() + { + _templateRenderer = GetRequiredService(); + } + + [Fact] + public async Task Should_Get_Rendered_Localized_Template_Content_With_Different_Cultures() + { + (await _templateRenderer.RenderAsync( + TestTemplates.WelcomeEmail, + model: new WelcomeEmailModel() + { + Name = "John" + }, + cultureName: "en" + )).ShouldBe("Welcome John to the abp.io!"); + + (await _templateRenderer.RenderAsync( + TestTemplates.WelcomeEmail, + model: new WelcomeEmailModel() + { + Name = "John" + }, + cultureName: "tr" + )).ShouldBe("Merhaba John, abp.io'ya hoşgeldiniz!"); + + //"en-US" fallbacks to "en" since "en-US" doesn't exists and "en" is the fallback culture + (await _templateRenderer.RenderAsync( + TestTemplates.WelcomeEmail, + model: new WelcomeEmailModel() + { + Name = "John" + }, + cultureName: "en-US" + )).ShouldBe("Welcome John to the abp.io!"); + + //"fr" fallbacks to "en" since "fr" doesn't exists and "en" is the default culture + (await _templateRenderer.RenderAsync( + TestTemplates.WelcomeEmail, + model: new WelcomeEmailModel() + { + Name = "John" + }, + cultureName: "fr" + )).ShouldBe("Welcome John to the abp.io!"); + } + + [Fact] + public async Task Should_Get_Rendered_Localized_Template_Content_With_Stronly_Typed_Model() + { + (await _templateRenderer.RenderAsync( + TestTemplates.WelcomeEmail, + model: new WelcomeEmailModel("John"), + cultureName: "en" + )).ShouldBe("Welcome John to the abp.io!"); + } + + [Fact] + public async Task Should_Get_Rendered_Inline_Localized_Template() + { + (await _templateRenderer.RenderAsync( + TestTemplates.ForgotPasswordEmail, + new ForgotPasswordEmailModel("John"), + cultureName: "en" + )).ShouldBe("*BEGIN*Hello John, how are you?. Please click to the following link to get an email to reset your password!*END*"); + + (await _templateRenderer.RenderAsync( + TestTemplates.ForgotPasswordEmail, + new ForgotPasswordEmailModel("John"), + cultureName: "tr" + )).ShouldBe("*BEGIN*Merhaba John, nasılsın?. Please click to the following link to get an email to reset your password!*END*"); + } + + [Fact] + public async Task Should_Get_Localized_Numbers() + { + (await _templateRenderer.RenderAsync( + TestTemplates.ShowDecimalNumber, + new ShowDecimalNumberModel(123.45M), + cultureName: "en" + )).ShouldBe("*BEGIN*123.45*END*"); + + (await _templateRenderer.RenderAsync( + TestTemplates.ShowDecimalNumber, + new ShowDecimalNumberModel(123.45M), + cultureName: "de" + )).ShouldBe("*BEGIN*123,45*END*"); + } + + public class WelcomeEmailModel + { + public string Name { get; set; } + + public WelcomeEmailModel() + { + + } + + public WelcomeEmailModel(string name) + { + Name = name; + } + } + + public class ForgotPasswordEmailModel + { + public string Name { get; set; } + + public ForgotPasswordEmailModel() + { + + } + + public ForgotPasswordEmailModel(string name) + { + Name = name; + } + } + + public class ShowDecimalNumberModel + { + public decimal Amount { get; set; } + + public ShowDecimalNumberModel() + { + + } + + public ShowDecimalNumberModel(decimal amount) + { + Amount = amount; + } + } + } +} diff --git a/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorTestTemplateDefinitionProvider.cs b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorTestTemplateDefinitionProvider.cs new file mode 100644 index 0000000000..5fdd0a786b --- /dev/null +++ b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorTestTemplateDefinitionProvider.cs @@ -0,0 +1,20 @@ +namespace Volo.Abp.TextTemplating.Razor +{ + public class RazorTestTemplateDefinitionProvider : TemplateDefinitionProvider + { + public override void Define(ITemplateDefinitionContext context) + { + context.GetOrNull(TestTemplates.WelcomeEmail)? + .WithVirtualFilePath("/SampleTemplates/WelcomeEmail", false); + + context.GetOrNull(TestTemplates.ForgotPasswordEmail)? + .WithVirtualFilePath("/SampleTemplates/ForgotPasswordEmail.cshtml", true); + + context.GetOrNull(TestTemplates.TestTemplateLayout1)? + .WithVirtualFilePath("/SampleTemplates/TestTemplateLayout1.cshtml", true); + + context.GetOrNull(TestTemplates.ShowDecimalNumber)? + .WithVirtualFilePath("/SampleTemplates/ShowDecimalNumber.cshtml", true); + } + } +} diff --git a/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorTextTemplatingTestModule.cs b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorTextTemplatingTestModule.cs new file mode 100644 index 0000000000..6832f88dfa --- /dev/null +++ b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorTextTemplatingTestModule.cs @@ -0,0 +1,26 @@ +using Microsoft.CodeAnalysis; +using Volo.Abp.Modularity; +using Volo.Abp.VirtualFileSystem; + +namespace Volo.Abp.TextTemplating.Razor +{ + [DependsOn( + typeof(AbpTextTemplatingRazorModule), + typeof(AbpTextTemplatingTestModule) + )] + public class RazorTextTemplatingTestModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.FileSets.AddEmbedded("Volo.Abp.TextTemplating.Razor"); + }); + + Configure(options => + { + options.References.Add(MetadataReference.CreateFromFile(typeof(RazorTextTemplatingTestModule).Assembly.Location)); + }); + } + } +} diff --git a/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorVirtualFileTemplateContributor_Tests.cs b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorVirtualFileTemplateContributor_Tests.cs new file mode 100644 index 0000000000..5634ccfa2c --- /dev/null +++ b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorVirtualFileTemplateContributor_Tests.cs @@ -0,0 +1,23 @@ +using System; +using Volo.Abp.TextTemplating.VirtualFiles; + +namespace Volo.Abp.TextTemplating.Razor +{ + public class RazorVirtualFileTemplateContributor_Tests : VirtualFileTemplateContributor_Tests + { + public RazorVirtualFileTemplateContributor_Tests() + { + WelcomeEmailEnglishContent = "@inherits Volo.Abp.TextTemplating.Razor.RazorTemplatePageBase" + + Environment.NewLine + + "Welcome @Model.Name to the abp.io!"; + + WelcomeEmailTurkishContent = "@inherits Volo.Abp.TextTemplating.Razor.RazorTemplatePageBase" + + Environment.NewLine + + "Merhaba @Model.Name, abp.io'ya hoşgeldiniz!"; + + ForgotPasswordEmailEnglishContent = "@inherits Volo.Abp.TextTemplating.Razor.RazorTemplatePageBase" + + Environment.NewLine + + "@Localizer[\"HelloText\", Model.Name], @Localizer[\"HowAreYou\"]. Please click to the following link to get an email to reset your password!"; + } + } +} diff --git a/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/ForgotPasswordEmail.cshtml b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/ForgotPasswordEmail.cshtml new file mode 100644 index 0000000000..e02bc728ab --- /dev/null +++ b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/ForgotPasswordEmail.cshtml @@ -0,0 +1,2 @@ +@inherits Volo.Abp.TextTemplating.Razor.RazorTemplatePageBase +@Localizer["HelloText", Model.Name], @Localizer["HowAreYou"]. Please click to the following link to get an email to reset your password! \ No newline at end of file diff --git a/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/ShowDecimalNumber.cshtml b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/ShowDecimalNumber.cshtml new file mode 100644 index 0000000000..d309dc5a2b --- /dev/null +++ b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/ShowDecimalNumber.cshtml @@ -0,0 +1,2 @@ +@inherits Volo.Abp.TextTemplating.Razor.RazorTemplatePageBase +@Model.Amount \ No newline at end of file diff --git a/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/TestTemplateLayout1.cshtml b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/TestTemplateLayout1.cshtml new file mode 100644 index 0000000000..4d3bc7b7c2 --- /dev/null +++ b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/TestTemplateLayout1.cshtml @@ -0,0 +1,2 @@ +@inherits Volo.Abp.TextTemplating.Razor.RazorTemplatePageBase +*BEGIN*@Body*END* \ No newline at end of file diff --git a/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/WelcomeEmail/en.cshtml b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/WelcomeEmail/en.cshtml new file mode 100644 index 0000000000..410bfe1240 --- /dev/null +++ b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/WelcomeEmail/en.cshtml @@ -0,0 +1,2 @@ +@inherits Volo.Abp.TextTemplating.Razor.RazorTemplatePageBase +Welcome @Model.Name to the abp.io! \ No newline at end of file diff --git a/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/WelcomeEmail/tr.cshtml b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/WelcomeEmail/tr.cshtml new file mode 100644 index 0000000000..7ea3c8802a --- /dev/null +++ b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/WelcomeEmail/tr.cshtml @@ -0,0 +1,2 @@ +@inherits Volo.Abp.TextTemplating.Razor.RazorTemplatePageBase +Merhaba @Model.Name, abp.io'ya hoşgeldiniz! \ No newline at end of file diff --git a/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo.Abp.TextTemplating.Scriban.Tests.csproj b/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo.Abp.TextTemplating.Scriban.Tests.csproj new file mode 100644 index 0000000000..d17a4d46fa --- /dev/null +++ b/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo.Abp.TextTemplating.Scriban.Tests.csproj @@ -0,0 +1,23 @@ + + + + + + net5.0 + + + + + + Always + + + + + + + + + + + diff --git a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/SampleTemplates/ForgotPasswordEmail.tpl b/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/SampleTemplates/ForgotPasswordEmail.tpl similarity index 100% rename from framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/SampleTemplates/ForgotPasswordEmail.tpl rename to framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/SampleTemplates/ForgotPasswordEmail.tpl diff --git a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/SampleTemplates/ShowDecimalNumber.tpl b/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/SampleTemplates/ShowDecimalNumber.tpl similarity index 100% rename from framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/SampleTemplates/ShowDecimalNumber.tpl rename to framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/SampleTemplates/ShowDecimalNumber.tpl diff --git a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/SampleTemplates/TestTemplateLayout1.tpl b/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/SampleTemplates/TestTemplateLayout1.tpl similarity index 100% rename from framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/SampleTemplates/TestTemplateLayout1.tpl rename to framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/SampleTemplates/TestTemplateLayout1.tpl diff --git a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/SampleTemplates/WelcomeEmail/en.tpl b/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/SampleTemplates/WelcomeEmail/en.tpl similarity index 100% rename from framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/SampleTemplates/WelcomeEmail/en.tpl rename to framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/SampleTemplates/WelcomeEmail/en.tpl diff --git a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/SampleTemplates/WelcomeEmail/tr.tpl b/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/SampleTemplates/WelcomeEmail/tr.tpl similarity index 100% rename from framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/SampleTemplates/WelcomeEmail/tr.tpl rename to framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/SampleTemplates/WelcomeEmail/tr.tpl diff --git a/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanLocalizedTemplateContentReaderFactory_Tests.cs b/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanLocalizedTemplateContentReaderFactory_Tests.cs new file mode 100644 index 0000000000..1757bdaa17 --- /dev/null +++ b/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanLocalizedTemplateContentReaderFactory_Tests.cs @@ -0,0 +1,20 @@ +using System.IO; +using Microsoft.Extensions.FileProviders; +using Volo.Abp.TextTemplating.VirtualFiles; + +namespace Volo.Abp.TextTemplating.Scriban +{ + public class ScribanLocalizedTemplateContentReaderFactory_Tests : LocalizedTemplateContentReaderFactory_Tests + { + public ScribanLocalizedTemplateContentReaderFactory_Tests() + { + LocalizedTemplateContentReaderFactory = new LocalizedTemplateContentReaderFactory( + new PhysicalFileVirtualFileProvider( + new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), + "Volo", "Abp", "TextTemplating", "Scriban")))); + + WelcomeEmailEnglishContent = "Welcome {{model.name}} to the abp.io!"; + WelcomeEmailTurkishContent = "Merhaba {{model.name}}, abp.io'ya hoşgeldiniz!"; + } + } +} diff --git a/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanTemplateDefinitionTests.cs b/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanTemplateDefinitionTests.cs new file mode 100644 index 0000000000..e454af36ef --- /dev/null +++ b/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanTemplateDefinitionTests.cs @@ -0,0 +1,7 @@ +namespace Volo.Abp.TextTemplating.Scriban +{ + public class ScribanTemplateDefinitionTests : TemplateDefinitionTests + { + + } +} diff --git a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TemplateRenderer_Tests.cs b/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanTemplateRenderer_Tests.cs similarity index 95% rename from framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TemplateRenderer_Tests.cs rename to framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanTemplateRenderer_Tests.cs index ca4ae3e3fd..a076301919 100644 --- a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TemplateRenderer_Tests.cs +++ b/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanTemplateRenderer_Tests.cs @@ -3,13 +3,13 @@ using System.Threading.Tasks; using Shouldly; using Xunit; -namespace Volo.Abp.TextTemplating +namespace Volo.Abp.TextTemplating.Scriban { - public class TemplateRenderer_Tests : AbpTextTemplatingTestBase + public class ScribanTemplateRenderer_Tests : AbpTextTemplatingTestBase { private readonly ITemplateRenderer _templateRenderer; - public TemplateRenderer_Tests() + public ScribanTemplateRenderer_Tests() { _templateRenderer = GetRequiredService(); } @@ -91,7 +91,7 @@ namespace Volo.Abp.TextTemplating cultureName: "tr" )).ShouldBe("*BEGIN*Merhaba John, nasılsın?. Please click to the following link to get an email to reset your password!*END*"); } - + [Fact] public async Task Should_Get_Localized_Numbers() { diff --git a/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanTestTemplateDefinitionProvider.cs b/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanTestTemplateDefinitionProvider.cs new file mode 100644 index 0000000000..956c376fd0 --- /dev/null +++ b/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanTestTemplateDefinitionProvider.cs @@ -0,0 +1,20 @@ +namespace Volo.Abp.TextTemplating.Scriban +{ + public class ScribanTestTemplateDefinitionProvider : TemplateDefinitionProvider + { + public override void Define(ITemplateDefinitionContext context) + { + context.GetOrNull(TestTemplates.WelcomeEmail)? + .WithVirtualFilePath("/SampleTemplates/WelcomeEmail", false); + + context.GetOrNull(TestTemplates.ForgotPasswordEmail)? + .WithVirtualFilePath("/SampleTemplates/ForgotPasswordEmail.tpl", true); + + context.GetOrNull(TestTemplates.TestTemplateLayout1)? + .WithVirtualFilePath("/SampleTemplates/TestTemplateLayout1.tpl", true); + + context.GetOrNull(TestTemplates.ShowDecimalNumber)? + .WithVirtualFilePath("/SampleTemplates/ShowDecimalNumber.tpl", true); + } + } +} diff --git a/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanTextTemplatingTestModule.cs b/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanTextTemplatingTestModule.cs new file mode 100644 index 0000000000..2ed2e51b56 --- /dev/null +++ b/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanTextTemplatingTestModule.cs @@ -0,0 +1,20 @@ +using Volo.Abp.Modularity; +using Volo.Abp.VirtualFileSystem; + +namespace Volo.Abp.TextTemplating.Scriban +{ + [DependsOn( + typeof(AbpTextTemplatingScribanModule), + typeof(AbpTextTemplatingTestModule) + )] + public class ScribanTextTemplatingTestModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.FileSets.AddEmbedded("Volo.Abp.TextTemplating.Scriban"); + }); + } + } +} diff --git a/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanVirtualFileTemplateContributor_Tests.cs b/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanVirtualFileTemplateContributor_Tests.cs new file mode 100644 index 0000000000..026b8abe59 --- /dev/null +++ b/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanVirtualFileTemplateContributor_Tests.cs @@ -0,0 +1,14 @@ +using Volo.Abp.TextTemplating.VirtualFiles; + +namespace Volo.Abp.TextTemplating.Scriban +{ + public class ScribanVirtualFileTemplateContributor_Tests : VirtualFileTemplateContributor_Tests + { + public ScribanVirtualFileTemplateContributor_Tests() + { + WelcomeEmailEnglishContent = "Welcome {{model.name}} to the abp.io!"; + WelcomeEmailTurkishContent = "Merhaba {{model.name}}, abp.io'ya hoşgeldiniz!"; + ForgotPasswordEmailEnglishContent = "{{L \"HelloText\" model.name}}, {{L \"HowAreYou\" }}. Please click to the following link to get an email to reset your password!"; + } + } +} diff --git a/framework/test/Volo.Abp.TextTemplating.Tests/Volo.Abp.TextTemplating.Tests.csproj b/framework/test/Volo.Abp.TextTemplating.Tests/Volo.Abp.TextTemplating.Tests.csproj index 555c2934b0..65983605be 100644 --- a/framework/test/Volo.Abp.TextTemplating.Tests/Volo.Abp.TextTemplating.Tests.csproj +++ b/framework/test/Volo.Abp.TextTemplating.Tests/Volo.Abp.TextTemplating.Tests.csproj @@ -10,15 +10,12 @@ - - Always - - + diff --git a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/AbpTextTemplatingOptions_Tests.cs b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/AbpTextTemplatingOptions_Tests.cs index 294596c693..591f6c9caf 100644 --- a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/AbpTextTemplatingOptions_Tests.cs +++ b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/AbpTextTemplatingOptions_Tests.cs @@ -4,7 +4,7 @@ using Xunit; namespace Volo.Abp.TextTemplating { - public class AbpTextTemplatingOptions_Tests : AbpTextTemplatingTestBase + public class AbpTextTemplatingOptions_Tests : AbpTextTemplatingTestBase { private readonly AbpTextTemplatingOptions _options; @@ -21,4 +21,4 @@ namespace Volo.Abp.TextTemplating .ShouldContain(typeof(TestTemplateDefinitionProvider)); } } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/AbpTextTemplatingTestBase.cs b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/AbpTextTemplatingTestBase.cs index ca5dc20445..24f8bad395 100644 --- a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/AbpTextTemplatingTestBase.cs +++ b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/AbpTextTemplatingTestBase.cs @@ -1,8 +1,10 @@ -using Volo.Abp.Testing; +using Volo.Abp.Modularity; +using Volo.Abp.Testing; namespace Volo.Abp.TextTemplating { - public abstract class AbpTextTemplatingTestBase : AbpIntegratedTest + public abstract class AbpTextTemplatingTestBase : AbpIntegratedTest + where TStartupModule : IAbpModule { protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) { diff --git a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/AbpTextTemplatingTestModule.cs b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/AbpTextTemplatingTestModule.cs index 8e8b69e116..74174ea690 100644 --- a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/AbpTextTemplatingTestModule.cs +++ b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/AbpTextTemplatingTestModule.cs @@ -7,7 +7,7 @@ using Volo.Abp.VirtualFileSystem; namespace Volo.Abp.TextTemplating { [DependsOn( - typeof(AbpTextTemplatingModule), + typeof(AbpTextTemplatingAbstractionsModule), typeof(AbpTestBaseModule), typeof(AbpAutofacModule), typeof(AbpLocalizationModule) diff --git a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TemplateDefinitionTests.cs b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TemplateDefinitionTests.cs index 51c78cc13e..6fd97cd2d4 100644 --- a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TemplateDefinitionTests.cs +++ b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TemplateDefinitionTests.cs @@ -1,25 +1,27 @@ using Shouldly; +using Volo.Abp.Modularity; using Xunit; namespace Volo.Abp.TextTemplating { - public class TemplateDefinitionTests : AbpTextTemplatingTestBase + public abstract class TemplateDefinitionTests : AbpTextTemplatingTestBase + where TStartupModule : IAbpModule { - private readonly ITemplateDefinitionManager _templateDefinitionManager; + protected readonly ITemplateDefinitionManager TemplateDefinitionManager; - public TemplateDefinitionTests() + protected TemplateDefinitionTests() { - _templateDefinitionManager = GetRequiredService(); + TemplateDefinitionManager = GetRequiredService(); } [Fact] public void Should_Retrieve_Template_Definition_By_Name() { - var welcomeEmailTemplate = _templateDefinitionManager.Get(TestTemplates.WelcomeEmail); + var welcomeEmailTemplate = TemplateDefinitionManager.Get(TestTemplates.WelcomeEmail); welcomeEmailTemplate.Name.ShouldBe(TestTemplates.WelcomeEmail); welcomeEmailTemplate.IsInlineLocalized.ShouldBeFalse(); - var forgotPasswordEmailTemplate = _templateDefinitionManager.Get(TestTemplates.ForgotPasswordEmail); + var forgotPasswordEmailTemplate = TemplateDefinitionManager.Get(TestTemplates.ForgotPasswordEmail); forgotPasswordEmailTemplate.Name.ShouldBe(TestTemplates.ForgotPasswordEmail); forgotPasswordEmailTemplate.IsInlineLocalized.ShouldBeTrue(); } @@ -27,15 +29,15 @@ namespace Volo.Abp.TextTemplating [Fact] public void Should_Get_Null_If_Template_Not_Found() { - var definition = _templateDefinitionManager.GetOrNull("undefined-template"); + var definition = TemplateDefinitionManager.GetOrNull("undefined-template"); definition.ShouldBeNull(); } [Fact] public void Should_Retrieve_All_Template_Definitions() { - var definitions = _templateDefinitionManager.GetAll(); + var definitions = TemplateDefinitionManager.GetAll(); definitions.Count.ShouldBeGreaterThan(1); } } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TestTemplateDefinitionProvider.cs b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TestTemplateDefinitionProvider.cs index 9db711d70c..289bf1b04f 100644 --- a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TestTemplateDefinitionProvider.cs +++ b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TestTemplateDefinitionProvider.cs @@ -10,7 +10,7 @@ namespace Volo.Abp.TextTemplating new TemplateDefinition( TestTemplates.WelcomeEmail, defaultCultureName: "en" - ).WithVirtualFilePath("/SampleTemplates/WelcomeEmail", false) + ) ); context.Add( @@ -18,22 +18,22 @@ namespace Volo.Abp.TextTemplating TestTemplates.ForgotPasswordEmail, localizationResource: typeof(TestLocalizationSource), layout: TestTemplates.TestTemplateLayout1 - ).WithVirtualFilePath("/SampleTemplates/ForgotPasswordEmail.tpl", true) + ) ); context.Add( new TemplateDefinition( TestTemplates.TestTemplateLayout1, isLayout: true - ).WithVirtualFilePath("/SampleTemplates/TestTemplateLayout1.tpl", true) + ) ); - + context.Add( new TemplateDefinition( TestTemplates.ShowDecimalNumber, localizationResource: typeof(TestLocalizationSource), layout: TestTemplates.TestTemplateLayout1 - ).WithVirtualFilePath("/SampleTemplates/ShowDecimalNumber.tpl", true) + ) ); } } diff --git a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/VirtualFiles/LocalizedTemplateContentReaderFactory_Tests.cs b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/VirtualFiles/LocalizedTemplateContentReaderFactory_Tests.cs index 63e526ac1d..7a56997031 100644 --- a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/VirtualFiles/LocalizedTemplateContentReaderFactory_Tests.cs +++ b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/VirtualFiles/LocalizedTemplateContentReaderFactory_Tests.cs @@ -1,37 +1,36 @@ -using System.IO; -using System.Threading.Tasks; +using System.Threading.Tasks; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Primitives; using Shouldly; +using Volo.Abp.Modularity; using Volo.Abp.VirtualFileSystem; using Xunit; namespace Volo.Abp.TextTemplating.VirtualFiles { - public class LocalizedTemplateContentReaderFactory_Tests: AbpTextTemplatingTestBase + public abstract class LocalizedTemplateContentReaderFactory_Tests : AbpTextTemplatingTestBase + where TStartupModule : IAbpModule { - private readonly ITemplateDefinitionManager _templateDefinitionManager; + protected readonly ITemplateDefinitionManager TemplateDefinitionManager; + protected LocalizedTemplateContentReaderFactory LocalizedTemplateContentReaderFactory; + protected string WelcomeEmailEnglishContent; + protected string WelcomeEmailTurkishContent; - public LocalizedTemplateContentReaderFactory_Tests() + protected LocalizedTemplateContentReaderFactory_Tests() { - _templateDefinitionManager = GetRequiredService(); + TemplateDefinitionManager = GetRequiredService(); } [Fact] public async Task Create_Should_Work_With_PhysicalFileProvider() { - var localizedTemplateContentReaderFactory = new LocalizedTemplateContentReaderFactory( - new PhysicalFileVirtualFileProvider( - new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), - "Volo", "Abp", "TextTemplating")))); + var reader = await LocalizedTemplateContentReaderFactory.CreateAsync(TemplateDefinitionManager.Get(TestTemplates.WelcomeEmail)); - var reader = await localizedTemplateContentReaderFactory.CreateAsync(_templateDefinitionManager.Get(TestTemplates.WelcomeEmail)); - - reader.GetContentOrNull("en").ShouldBe("Welcome {{model.name}} to the abp.io!"); - reader.GetContentOrNull("tr").ShouldBe("Merhaba {{model.name}}, abp.io'ya hoşgeldiniz!"); + reader.GetContentOrNull("en").ShouldBe(WelcomeEmailEnglishContent); + reader.GetContentOrNull("tr").ShouldBe(WelcomeEmailTurkishContent); } - class PhysicalFileVirtualFileProvider : IVirtualFileProvider + public class PhysicalFileVirtualFileProvider : IVirtualFileProvider { private readonly PhysicalFileProvider _physicalFileProvider; diff --git a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/VirtualFiles/VirtualFileTemplateContributor_Tests.cs b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/VirtualFiles/VirtualFileTemplateContributor_Tests.cs index e5c7138118..4862e61203 100644 --- a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/VirtualFiles/VirtualFileTemplateContributor_Tests.cs +++ b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/VirtualFiles/VirtualFileTemplateContributor_Tests.cs @@ -1,45 +1,50 @@ using System.Threading.Tasks; using Shouldly; +using Volo.Abp.Modularity; using Xunit; namespace Volo.Abp.TextTemplating.VirtualFiles { - public class VirtualFileTemplateContributor_Tests : AbpTextTemplatingTestBase + public abstract class VirtualFileTemplateContributor_Tests : AbpTextTemplatingTestBase + where TStartupModule : IAbpModule { - private readonly ITemplateDefinitionManager _templateDefinitionManager; - private readonly VirtualFileTemplateContentContributor _virtualFileTemplateContentContributor; + protected readonly ITemplateDefinitionManager TemplateDefinitionManager; + protected readonly VirtualFileTemplateContentContributor VirtualFileTemplateContentContributor; + protected string WelcomeEmailEnglishContent; + protected string WelcomeEmailTurkishContent; + protected string ForgotPasswordEmailEnglishContent; - public VirtualFileTemplateContributor_Tests() + protected VirtualFileTemplateContributor_Tests() { - _templateDefinitionManager = GetRequiredService(); - _virtualFileTemplateContentContributor = GetRequiredService(); + TemplateDefinitionManager = GetRequiredService(); + VirtualFileTemplateContentContributor = GetRequiredService(); } [Fact] public async Task Should_Get_Localized_Content_By_Culture() { - (await _virtualFileTemplateContentContributor.GetOrNullAsync( - new TemplateContentContributorContext(_templateDefinitionManager.Get(TestTemplates.WelcomeEmail), + (await VirtualFileTemplateContentContributor.GetOrNullAsync( + new TemplateContentContributorContext(TemplateDefinitionManager.Get(TestTemplates.WelcomeEmail), ServiceProvider, "en"))) - .ShouldBe("Welcome {{model.name}} to the abp.io!"); + .ShouldBe(WelcomeEmailEnglishContent); - (await _virtualFileTemplateContentContributor.GetOrNullAsync( - new TemplateContentContributorContext(_templateDefinitionManager.Get(TestTemplates.WelcomeEmail), + (await VirtualFileTemplateContentContributor.GetOrNullAsync( + new TemplateContentContributorContext(TemplateDefinitionManager.Get(TestTemplates.WelcomeEmail), ServiceProvider, "tr"))) - .ShouldBe("Merhaba {{model.name}}, abp.io'ya hoşgeldiniz!"); + .ShouldBe(WelcomeEmailTurkishContent); } [Fact] public async Task Should_Get_Non_Localized_Template_Content() { - (await _virtualFileTemplateContentContributor.GetOrNullAsync( + (await VirtualFileTemplateContentContributor.GetOrNullAsync( new TemplateContentContributorContext( - _templateDefinitionManager.Get(TestTemplates.ForgotPasswordEmail), + TemplateDefinitionManager.Get(TestTemplates.ForgotPasswordEmail), ServiceProvider, null))) - .ShouldBe("{{L \"HelloText\" model.name}}, {{L \"HowAreYou\" }}. Please click to the following link to get an email to reset your password!"); + .ShouldBe(ForgotPasswordEmailEnglishContent); } } } diff --git a/nupkg/common.ps1 b/nupkg/common.ps1 index c0e82e3486..e4ab829402 100644 --- a/nupkg/common.ps1 +++ b/nupkg/common.ps1 @@ -138,7 +138,10 @@ $projects = ( "framework/src/Volo.Abp.Sms.Aliyun", "framework/src/Volo.Abp.Specifications", "framework/src/Volo.Abp.TestBase", + "framework/src/Volo.Abp.TextTemplating.Abstractions", "framework/src/Volo.Abp.TextTemplating", + "framework/src/Volo.Abp.TextTemplating.Razor", + "framework/src/Volo.Abp.TextTemplating.Scriban", "framework/src/Volo.Abp.Threading", "framework/src/Volo.Abp.Timing", "framework/src/Volo.Abp.UI",