From 6d38c9f5000b65e2633dd1864266f60e9b33a32c Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 5 Apr 2021 15:06:07 +0800 Subject: [PATCH 1/7] Razor engine support for text templating Resolve #8373 --- framework/Volo.Abp.sln | 35 ++++ .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 +++ ...olo.Abp.TextTemplating.Abstractions.csproj | 16 ++ .../AbpTextTemplatingAbstractionsModule.cs | 46 +++++ .../AbpTextTemplatingOptions.cs | 0 .../ITemplateContentContributor.cs | 0 .../ITemplateContentProvider.cs | 0 .../ITemplateDefinitionContext.cs | 0 .../ITemplateDefinitionManager.cs | 0 .../ITemplateDefinitionProvider.cs | 0 .../Abp/TextTemplating/ITemplateRenderer.cs | 0 .../TemplateContentContributorContext.cs | 0 .../TextTemplating/TemplateContentProvider.cs | 0 .../Abp/TextTemplating/TemplateDefinition.cs | 0 .../TemplateDefinitionContext.cs | 0 .../TemplateDefinitionExtensions.cs | 0 .../TemplateDefinitionManager.cs | 0 .../TemplateDefinitionProvider.cs | 0 .../FileInfoLocalizedTemplateContentReader.cs | 0 .../ILocalizedTemplateContentReader.cs | 0 .../ILocalizedTemplateContentReaderFactory.cs | 0 .../LocalizedTemplateContentReaderFactory.cs | 3 +- .../NullLocalizedTemplateContentReader.cs | 0 .../VirtualFileTemplateContentContributor.cs | 0 ...ualFolderLocalizedTemplateContentReader.cs | 8 +- .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 +++ .../Volo.Abp.TextTemplating.Razor.csproj | 21 +++ .../Razor/AbpRazorTemplateConsts.cs | 9 + .../Razor/AbpTextTemplatingRazorModule.cs | 12 ++ .../TextTemplating/Razor/CSharpCompiler.cs | 107 +++++++++++ .../Razor/CSharpCompilerOptions.cs | 15 ++ .../Razor/DefaultCompiledViewProvider.cs | 64 +++++++ .../Razor/DefaultRazorProjectEngineFactory.cs | 20 ++ .../Razor/EmptyProjectFileSystem.cs | 30 +++ .../Razor/ICompiledViewProvider.cs | 10 + .../Razor/IRazorProjectEngineFactory.cs | 11 ++ .../Razor/IRazorTemplatePage.cs | 34 ++++ .../Razor/NotFoundProjectItem.cs | 28 +++ .../Razor/RazorTemplatePageBase.cs | 177 ++++++++++++++++++ .../Razor/RazorTemplateRenderer.cs | 168 +++++++++++++++++ .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 +++ .../Volo.Abp.TextTemplating.Scriban.csproj | 19 ++ .../Scriban/AbpTextTemplatingScribanModule.cs | 12 ++ .../Scriban/ScribanTemplateLocalizer.cs} | 6 +- .../Scriban/ScribanTemplateRenderer.cs} | 12 +- .../Volo.Abp.TextTemplating.csproj | 13 +- .../TextTemplating/AbpTextTemplatingModule.cs | 39 +--- ...Volo.Abp.TextTemplating.Razor.Tests.csproj | 23 +++ ...lizedTemplateContentReaderFactory_Tests.cs | 26 +++ .../Razor/RazorTemplateDefinitionTests.cs | 7 + .../Razor/RazorTemplateRenderer_Tests.cs | 145 ++++++++++++++ .../RazorTestTemplateDefinitionProvider.cs | 20 ++ .../Razor/RazorTextTemplatingTestModule.cs | 26 +++ ...zorVirtualFileTemplateContributor_Tests.cs | 23 +++ .../ForgotPasswordEmail.cshtml | 2 + .../SampleTemplates/ShowDecimalNumber.cshtml | 2 + .../TestTemplateLayout1.cshtml | 2 + .../SampleTemplates/WelcomeEmail/en.cshtml | 2 + .../SampleTemplates/WelcomeEmail/tr.cshtml | 2 + ...lo.Abp.TextTemplating.Scriban.Tests.csproj | 23 +++ .../SampleTemplates/ForgotPasswordEmail.tpl | 0 .../SampleTemplates/ShowDecimalNumber.tpl | 0 .../SampleTemplates/TestTemplateLayout1.tpl | 0 .../SampleTemplates/WelcomeEmail/en.tpl | 0 .../SampleTemplates/WelcomeEmail/tr.tpl | 0 ...lizedTemplateContentReaderFactory_Tests.cs | 20 ++ .../Scriban/ScribanTemplateDefinitionTests.cs | 7 + .../Scriban/ScribanTemplateRenderer_Tests.cs} | 8 +- .../ScribanTestTemplateDefinitionProvider.cs | 20 ++ .../ScribanTextTemplatingTestModule.cs | 20 ++ ...banVirtualFileTemplateContributor_Tests.cs | 14 ++ .../Volo.Abp.TextTemplating.Tests.csproj | 5 +- .../AbpTextTemplatingOptions_Tests.cs | 4 +- .../AbpTextTemplatingTestBase.cs | 6 +- .../AbpTextTemplatingTestModule.cs | 2 +- .../TextTemplating/TemplateDefinitionTests.cs | 20 +- .../TestTemplateDefinitionProvider.cs | 10 +- ...lizedTemplateContentReaderFactory_Tests.cs | 29 ++- .../VirtualFileTemplateContributor_Tests.cs | 35 ++-- nupkg/common.ps1 | 3 + 83 files changed, 1401 insertions(+), 119 deletions(-) create mode 100644 framework/src/Volo.Abp.TextTemplating.Abstractions/FodyWeavers.xml create mode 100644 framework/src/Volo.Abp.TextTemplating.Abstractions/FodyWeavers.xsd create mode 100644 framework/src/Volo.Abp.TextTemplating.Abstractions/Volo.Abp.TextTemplating.Abstractions.csproj create mode 100644 framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/AbpTextTemplatingAbstractionsModule.cs rename framework/src/{Volo.Abp.TextTemplating => Volo.Abp.TextTemplating.Abstractions}/Volo/Abp/TextTemplating/AbpTextTemplatingOptions.cs (100%) rename framework/src/{Volo.Abp.TextTemplating => Volo.Abp.TextTemplating.Abstractions}/Volo/Abp/TextTemplating/ITemplateContentContributor.cs (100%) rename framework/src/{Volo.Abp.TextTemplating => Volo.Abp.TextTemplating.Abstractions}/Volo/Abp/TextTemplating/ITemplateContentProvider.cs (100%) rename framework/src/{Volo.Abp.TextTemplating => Volo.Abp.TextTemplating.Abstractions}/Volo/Abp/TextTemplating/ITemplateDefinitionContext.cs (100%) rename framework/src/{Volo.Abp.TextTemplating => Volo.Abp.TextTemplating.Abstractions}/Volo/Abp/TextTemplating/ITemplateDefinitionManager.cs (100%) rename framework/src/{Volo.Abp.TextTemplating => Volo.Abp.TextTemplating.Abstractions}/Volo/Abp/TextTemplating/ITemplateDefinitionProvider.cs (100%) rename framework/src/{Volo.Abp.TextTemplating => Volo.Abp.TextTemplating.Abstractions}/Volo/Abp/TextTemplating/ITemplateRenderer.cs (100%) rename framework/src/{Volo.Abp.TextTemplating => Volo.Abp.TextTemplating.Abstractions}/Volo/Abp/TextTemplating/TemplateContentContributorContext.cs (100%) rename framework/src/{Volo.Abp.TextTemplating => Volo.Abp.TextTemplating.Abstractions}/Volo/Abp/TextTemplating/TemplateContentProvider.cs (100%) rename framework/src/{Volo.Abp.TextTemplating => Volo.Abp.TextTemplating.Abstractions}/Volo/Abp/TextTemplating/TemplateDefinition.cs (100%) rename framework/src/{Volo.Abp.TextTemplating => Volo.Abp.TextTemplating.Abstractions}/Volo/Abp/TextTemplating/TemplateDefinitionContext.cs (100%) rename framework/src/{Volo.Abp.TextTemplating => Volo.Abp.TextTemplating.Abstractions}/Volo/Abp/TextTemplating/TemplateDefinitionExtensions.cs (100%) rename framework/src/{Volo.Abp.TextTemplating => Volo.Abp.TextTemplating.Abstractions}/Volo/Abp/TextTemplating/TemplateDefinitionManager.cs (100%) rename framework/src/{Volo.Abp.TextTemplating => Volo.Abp.TextTemplating.Abstractions}/Volo/Abp/TextTemplating/TemplateDefinitionProvider.cs (100%) rename framework/src/{Volo.Abp.TextTemplating => Volo.Abp.TextTemplating.Abstractions}/Volo/Abp/TextTemplating/VirtualFiles/FileInfoLocalizedTemplateContentReader.cs (100%) rename framework/src/{Volo.Abp.TextTemplating => Volo.Abp.TextTemplating.Abstractions}/Volo/Abp/TextTemplating/VirtualFiles/ILocalizedTemplateContentReader.cs (100%) rename framework/src/{Volo.Abp.TextTemplating => Volo.Abp.TextTemplating.Abstractions}/Volo/Abp/TextTemplating/VirtualFiles/ILocalizedTemplateContentReaderFactory.cs (100%) rename framework/src/{Volo.Abp.TextTemplating => Volo.Abp.TextTemplating.Abstractions}/Volo/Abp/TextTemplating/VirtualFiles/LocalizedTemplateContentReaderFactory.cs (96%) rename framework/src/{Volo.Abp.TextTemplating => Volo.Abp.TextTemplating.Abstractions}/Volo/Abp/TextTemplating/VirtualFiles/NullLocalizedTemplateContentReader.cs (100%) rename framework/src/{Volo.Abp.TextTemplating => Volo.Abp.TextTemplating.Abstractions}/Volo/Abp/TextTemplating/VirtualFiles/VirtualFileTemplateContentContributor.cs (100%) rename framework/src/{Volo.Abp.TextTemplating => Volo.Abp.TextTemplating.Abstractions}/Volo/Abp/TextTemplating/VirtualFiles/VirtualFolderLocalizedTemplateContentReader.cs (80%) create mode 100644 framework/src/Volo.Abp.TextTemplating.Razor/FodyWeavers.xml create mode 100644 framework/src/Volo.Abp.TextTemplating.Razor/FodyWeavers.xsd create mode 100644 framework/src/Volo.Abp.TextTemplating.Razor/Volo.Abp.TextTemplating.Razor.csproj create mode 100644 framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/AbpRazorTemplateConsts.cs create mode 100644 framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/AbpTextTemplatingRazorModule.cs create mode 100644 framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/CSharpCompiler.cs create mode 100644 framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/CSharpCompilerOptions.cs create mode 100644 framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultCompiledViewProvider.cs create mode 100644 framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultRazorProjectEngineFactory.cs create mode 100644 framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/EmptyProjectFileSystem.cs create mode 100644 framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/ICompiledViewProvider.cs create mode 100644 framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/IRazorProjectEngineFactory.cs create mode 100644 framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/IRazorTemplatePage.cs create mode 100644 framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/NotFoundProjectItem.cs create mode 100644 framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/RazorTemplatePageBase.cs create mode 100644 framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/RazorTemplateRenderer.cs create mode 100644 framework/src/Volo.Abp.TextTemplating.Scriban/FodyWeavers.xml create mode 100644 framework/src/Volo.Abp.TextTemplating.Scriban/FodyWeavers.xsd create mode 100644 framework/src/Volo.Abp.TextTemplating.Scriban/Volo.Abp.TextTemplating.Scriban.csproj create mode 100644 framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/AbpTextTemplatingScribanModule.cs rename framework/src/{Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateLocalizer.cs => Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/ScribanTemplateLocalizer.cs} (91%) rename framework/src/{Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateRenderer.cs => Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/ScribanTemplateRenderer.cs} (94%) create mode 100644 framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo.Abp.TextTemplating.Razor.Tests.csproj create mode 100644 framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorLocalizedTemplateContentReaderFactory_Tests.cs create mode 100644 framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorTemplateDefinitionTests.cs create mode 100644 framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorTemplateRenderer_Tests.cs create mode 100644 framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorTestTemplateDefinitionProvider.cs create mode 100644 framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorTextTemplatingTestModule.cs create mode 100644 framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorVirtualFileTemplateContributor_Tests.cs create mode 100644 framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/ForgotPasswordEmail.cshtml create mode 100644 framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/ShowDecimalNumber.cshtml create mode 100644 framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/TestTemplateLayout1.cshtml create mode 100644 framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/WelcomeEmail/en.cshtml create mode 100644 framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/WelcomeEmail/tr.cshtml create mode 100644 framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo.Abp.TextTemplating.Scriban.Tests.csproj rename framework/test/{Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating => Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban}/SampleTemplates/ForgotPasswordEmail.tpl (100%) rename framework/test/{Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating => Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban}/SampleTemplates/ShowDecimalNumber.tpl (100%) rename framework/test/{Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating => Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban}/SampleTemplates/TestTemplateLayout1.tpl (100%) rename framework/test/{Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating => Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban}/SampleTemplates/WelcomeEmail/en.tpl (100%) rename framework/test/{Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating => Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban}/SampleTemplates/WelcomeEmail/tr.tpl (100%) create mode 100644 framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanLocalizedTemplateContentReaderFactory_Tests.cs create mode 100644 framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanTemplateDefinitionTests.cs rename framework/test/{Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TemplateRenderer_Tests.cs => Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanTemplateRenderer_Tests.cs} (95%) create mode 100644 framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanTestTemplateDefinitionProvider.cs create mode 100644 framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanTextTemplatingTestModule.cs create mode 100644 framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanVirtualFileTemplateContributor_Tests.cs 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", From 6cd793c091b10db4bfb998a5b93c347925fba458 Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 5 Apr 2021 16:10:33 +0800 Subject: [PATCH 2/7] Add razor integration document. --- docs/en/Text-Templating-Razor.md | 539 ++++++++++++++++++++++++++++ docs/en/Text-Templating-Scriban.md | 517 +++++++++++++++++++++++++++ docs/en/Text-Templating.md | 540 +---------------------------- docs/en/docs-nav.json | 12 +- 4 files changed, 1073 insertions(+), 535 deletions(-) create mode 100644 docs/en/Text-Templating-Razor.md create mode 100644 docs/en/Text-Templating-Scriban.md diff --git a/docs/en/Text-Templating-Razor.md b/docs/en/Text-Templating-Razor.md new file mode 100644 index 0000000000..6c4f9080c6 --- /dev/null +++ b/docs/en/Text-Templating-Razor.md @@ -0,0 +1,539 @@ +# Razor Integration + +## Installation + +It is suggested to use the [ABP CLI](CLI.md) to install this package. + +### Using the ABP CLI + +Open a command line window in the folder of the project (.csproj file) and type the following command: + +````bash +abp add-package Volo.Abp.TextTemplating.Razor +```` + +### Manual Installation + +If you want to manually install; + +1. Add the [Volo.Abp.TextTemplating.Razor](https://www.nuget.org/packages/Volo.Abp.TextTemplating.Razor) NuGet package to your project: + +```` +Install-Package Volo.Abp.TextTemplating.Razor +```` + +2. Add the `AbpTextTemplatingRazorModule` to the dependency list of your module: + +````csharp +[DependsOn( + //...other dependencies + typeof(AbpTextTemplatingRazorModule) //Add the new module dependency + )] +public class YourModule : AbpModule +{ +} +```` + +## Add MetadataReference to CSharpCompilerOptions + +You need to add the `MetadataReference` of the type used in the template to `CSharpCompilerOptions's References`. + +````csharp +public override void ConfigureServices(ServiceConfigurationContext context) +{ + Configure(options => + { + options.References.Add(MetadataReference.CreateFromFile(typeof(YourModule).Assembly.Location)); + }); +} +```` + +## Defining Templates + +Before rendering a template, you should define it. Create a class inheriting from the `TemplateDefinitionProvider` base class: + +````csharp +public class DemoTemplateDefinitionProvider : TemplateDefinitionProvider +{ + public override void Define(ITemplateDefinitionContext context) + { + context.Add( + new TemplateDefinition("Hello") //template name: "Hello" + .WithVirtualFilePath( + "/Demos/Hello/Hello.cshtml", //template content path + isInlineLocalized: true + ) + ); + } +} +```` + +* `context` object is used to add new templates or get the templates defined by depended modules. Used `context.Add(...)` to define a new template. +* `TemplateDefinition` is the class represents a template. Each template must have a unique name (that will be used while you are rendering the template). +* `/Demos/Hello/Hello.cshtml` is the path of the template file. +* `isInlineLocalized` is used to declare if you are using a single template for all languages (`true`) or different templates for each language (`false`). See the Localization section below for more. + +### The Template Content + +`WithVirtualFilePath` indicates that we are using the [Virtual File System](Virtual-File-System.md) to store the template content. Create a `Hello.cshtml` file inside your project and mark it as "**embedded resource**" on the properties window: + +![hello-template-razor](images/hello-template-razor.png) + +Example `Hello.cshtml` content is shown below: + +```` +@inherits Volo.Abp.TextTemplating.Razor.RazorTemplatePageBase +Hello @Model.Name +```` + +The `HelloModel` class is: +````csharp +namespace HelloModelNamespace +{ + public class HelloModel + { + public string Name { get; set; } + } +} +```` + +The [Virtual File System](Virtual-File-System.md) requires to add your files in the `ConfigureServices` method of your [module](Module-Development-Basics.md) class: + +````csharp +Configure(options => +{ + options.FileSets.AddEmbedded("TextTemplateDemo"); +}); +```` + +* `TextTemplateDemoModule` is the module class that you define your template in. +* `TextTemplateDemo` is the root namespace of your project. + +## Rendering the Template + +`ITemplateRenderer` service is used to render a template content. + +### Example: Rendering a Simple Template + +````csharp +public class HelloDemo : ITransientDependency +{ + private readonly ITemplateRenderer _templateRenderer; + + public HelloDemo(ITemplateRenderer templateRenderer) + { + _templateRenderer = templateRenderer; + } + + public async Task RunAsync() + { + var result = await _templateRenderer.RenderAsync( + "Hello", //the template name + new HelloModel + { + Name = "John" + } + ); + + Console.WriteLine(result); + } +} +```` + +* `HelloDemo` is a simple class that injects the `ITemplateRenderer` in its constructor and uses it inside the `RunAsync` method. +* `RenderAsync` gets two fundamental parameters: + * `templateName`: The name of the template to be rendered (`Hello` in this example). + * `model`: An object that is used as the `model` inside the template (a `HelloModel` object in this example). + +The result shown below for this example: + +````csharp +Hello John :) +```` +## Localization + +It is possible to localize a template content based on the current culture. There are two types of localization options described in the following sections. + +### Inline localization + +Inline localization uses the [localization system](Localization.md) to localize texts inside templates. + +#### Example: Reset Password Link + +Assuming you need to send an email to a user to reset her/his password. Here, the model/template content: + +```` +namespace ResetMyPasswordModelNamespace +{ + public class ResetMyPasswordModel + { + public string Link { get; set; } + + public string Name { get; set; } + } +} +```` + +```` +@inherits Volo.Abp.TextTemplating.Razor.RazorTemplatePageBase +@Localizer["ResetMyPassword", Model.Name] +```` + +`Localizer` service is used to localize the given key based on the current user culture. You need to define the `ResetMyPassword` key inside your localization file: + +````json +"ResetMyPasswordTitle": "Reset my password", +"ResetMyPassword": "Hi {0}, Click here to reset your password" +```` + +You also need to declare the localization resource to be used with this template, inside your template definition provider class: + +````csharp +context.Add( + new TemplateDefinition( + "PasswordReset", //Template name + typeof(DemoResource) //LOCALIZATION RESOURCE + ).WithVirtualFilePath( + "/Demos/PasswordReset/PasswordReset.cshtml", //template content path + isInlineLocalized: true + ) +); +```` + +That's all. When you render this template like that: + +````csharp +var result = await _templateRenderer.RenderAsync( + "PasswordReset", //the template name + new PasswordResetModel + { + Name = "john", + Link = "https://abp.io/example-link?userId=123&token=ABC" + } +); +```` + +You will see the localized result: + +````csharp +Hi john, Click here to reset your password +```` + +> If you define the [default localization resource](Localization.md) for your application, then no need to declare the resource type for the template definition. + +### Multiple Contents Localization + +Instead of a single template that uses the localization system to localize the template, you may want to create different template files for each language. It can be needed if the template should be completely different for a specific culture rather than simple text localizations. + +#### Example: Welcome Email Template + +Assuming that you want to send a welcome email to your users, but want to define a completely different template based on the user culture. + +First, create a folder and put your templates inside it, like `en.cshtml`, `tr.cshtml`... one for each culture you support: + +![multiple-file-template-razor](images/multiple-file-template-razor.png) + +Then add your template definition in the template definition provider class: + +````csharp +context.Add( + new TemplateDefinition( + name: "WelcomeEmail", + defaultCultureName: "en" + ) + .WithVirtualFilePath( + "/Demos/WelcomeEmail/Templates", //template content folder + isInlineLocalized: false + ) +); +```` + +* Set **default culture name**, so it fallbacks to the default culture if there is no template for the desired culture. +* Specify **the template folder** rather than a single template file. +* Set `isInlineLocalized` to `false` for this case. + +That's all, you can render the template for the current culture: + +````csharp +var result = await _templateRenderer.RenderAsync("WelcomeEmail"); +```` + +> Skipped the modal for this example to keep it simple, but you can use models as just explained before. + +### Specify the Culture + +`ITemplateRenderer` service uses the current culture (`CultureInfo.CurrentUICulture`) if not specified. If you need, you can specify the culture as the `cultureName` parameter: + +````csharp +var result = await _templateRenderer.RenderAsync( + "WelcomeEmail", + cultureName: "en" +); +```` + +## Layout Templates + +Layout templates are used to create shared layouts among other templates. It is similar to the layout system in the ASP.NET Core MVC / Razor Pages. + +### Example: Email HTML Layout Template + +For example, you may want to create a single layout for all of your email templates. + +First, create a template file just like before: + +````csharp +@inherits Volo.Abp.TextTemplating.Razor.RazorTemplatePageBase + + + + + + + @Body + + +```` + +* A layout template must have a `Body` part as a place holder for the rendered child content. + +The register your template in the template definition provider: + +````csharp +context.Add( + new TemplateDefinition( + "EmailLayout", + isLayout: true //SET isLayout! + ).WithVirtualFilePath( + "/Demos/EmailLayout/EmailLayout.cshtml", + isInlineLocalized: true + ) +); +```` + +Now, you can use this template as the layout of any other template: + +````csharp +context.Add( + new TemplateDefinition( + name: "WelcomeEmail", + defaultCultureName: "en", + layout: "EmailLayout" //Set the LAYOUT + ).WithVirtualFilePath( + "/Demos/WelcomeEmail/Templates", + isInlineLocalized: false + ) +); +```` + +## Global Context + +ABP passes the `model` that can be used to access to the model inside the template. You can pass more global variables if you need. + +An example template content: + +````csharp +@inherits Volo.Abp.TextTemplating.Razor.RazorTemplatePageBase +A global object value: @GlobalContext["myGlobalObject"] +```` + +This template assumes that that is a `myGlobalObject` object in the template rendering context. You can provide it like shown below: + +````csharp +var result = await _templateRenderer.RenderAsync( + "GlobalContextUsage", + globalContext: new Dictionary + { + {"myGlobalObject", "TEST VALUE"} + } +); +```` + +The rendering result will be: + +```` +A global object value: TEST VALUE +```` + +## Replacing the Existing Templates + +It is possible to replace a template defined by a module that used in your application. In this way, you can customize the templates based on your requirements without changing the module code. + +### Option-1: Using the Virtual File System + +The [Virtual File System](Virtual-File-System.md) allows you to override any file by placing the same file into the same path in your project. + +#### Example: Replace the Standard Email Layout Template + +ABP Framework provides an [email sending system](Emailing.md) that internally uses the text templating to render the email content. It defines a standard email layout template in the `/Volo/Abp/Emailing/Templates/Layout.cshtml` path. The unique name of the template is `Abp.StandardEmailTemplates.Layout` and this string is defined as a constant on the `Volo.Abp.Emailing.Templates.StandardEmailTemplates` static class. + +Do the following steps to replace the template file with your own; + +**1)** Add a new file into the same location (`/Volo/Abp/Emailing/Templates/Layout.cshtml`) in your project: + +![replace-email-layout-razor](images/replace-email-layout-razor.png) + +**2)** Prepare your email layout template: + +````html +@inherits Volo.Abp.TextTemplating.Razor.RazorTemplatePageBase + + + + + + +

This my header

+ + @Body + +
+ This is my footer... +
+ + +```` + +This example simply adds a header and footer to the template and renders the content between them (see the *Layout Templates* section above to understand it). + +**3)** Configure the embedded resources in the `.csproj` file + +* Add [Microsoft.Extensions.FileProviders.Embedded](https://www.nuget.org/packages/Microsoft.Extensions.FileProviders.Embedded) NuGet package to the project. +* Add `true` into the `...` section of your `.csproj` file. +* Add the following code into your `.csproj` file: + +````xml + + + + +```` + +This makes the template files "embedded resource". + +**4)** Configure the virtual file system + +Configure the `AbpVirtualFileSystemOptions` in the `ConfigureServices` method of your [module](Module-Development-Basics.md) to add the embedded files into the virtual file system: + +```csharp +Configure(options => +{ + options.FileSets.AddEmbedded(); +}); +``` + +`BookStoreDomainModule` should be your module name, in this example code. + +> Be sure that your module (directly or indirectly) [depends on](Module-Development-Basics.md) the `AbpEmailingModule`. Because the VFS can override files based on the dependency order. + +Now, your template will be used when you want to render the email layout template. + +### Option-2: Using the Template Definition Provider + +You can create a template definition provider class that gets the email layout template and changes the virtual file path for the template. + +**Example: Use the `/MyTemplates/EmailLayout.cshtml` file instead of the standard template** + +```csharp +using Volo.Abp.DependencyInjection; +using Volo.Abp.Emailing.Templates; +using Volo.Abp.TextTemplating; + +namespace MyProject +{ + public class MyTemplateDefinitionProvider + : TemplateDefinitionProvider, ITransientDependency + { + public override void Define(ITemplateDefinitionContext context) + { + var emailLayoutTemplate = context.GetOrNull(StandardEmailTemplates.Layout); + + emailLayoutTemplate + .WithVirtualFilePath( + "/MyTemplates/EmailLayout.cshtml", + isInlineLocalized: true + ); + } + } +} +``` + +You should still add the file `/MyTemplates/EmailLayout.cshtml` to the virtual file system as explained before. This approach allows you to locate templates in any folder instead of the folder defined by the depended module. + +Beside the template content, you can manipulate the template definition properties, like `DisplayName`, `Layout` or `LocalizationSource`. + +## Advanced Features + +This section covers some internals and more advanced usages of the text templating system. + +### Template Content Provider + +`ITemplateRenderer` is used to render the template, which is what you want for most of the cases. However, you can use the `ITemplateContentProvider` to get the raw (not rendered) template contents. + +> `ITemplateContentProvider` is internally used by the `ITemplateRenderer` to get the raw template contents. + +Example: + +````csharp +public class TemplateContentDemo : ITransientDependency +{ + private readonly ITemplateContentProvider _templateContentProvider; + + public TemplateContentDemo(ITemplateContentProvider templateContentProvider) + { + _templateContentProvider = templateContentProvider; + } + + public async Task RunAsync() + { + var result = await _templateContentProvider + .GetContentOrNullAsync("Hello"); + + Console.WriteLine(result); + } +} +```` + +The result will be the raw template content: + +```` +@inherits Volo.Abp.TextTemplating.Razor.RazorTemplatePageBase +Hello @Model.Name +```` + +* `GetContentOrNullAsync` returns `null` if no content defined for the requested template. +* It can get a `cultureName` parameter that is used if template has different files for different cultures (see Multiple Contents Localization section above). + +### Template Content Contributor + +`ITemplateContentProvider` service uses `ITemplateContentContributor` implementations to find template contents. There is a single pre-implemented content contributor, `VirtualFileTemplateContentContributor`, which gets template contents from the virtual file system as described above. + +You can implement the `ITemplateContentContributor` to read raw template contents from another source. + +Example: + +````csharp +public class MyTemplateContentProvider + : ITemplateContentContributor, ITransientDependency +{ + public async Task GetOrNullAsync(TemplateContentContributorContext context) + { + var templateName = context.TemplateDefinition.Name; + + //TODO: Try to find content from another source + return null; + } +} + +```` + +Return `null` if your source can not find the content, so `ITemplateContentProvider` fallbacks to the next contributor. + +### Template Definition Manager + +`ITemplateDefinitionManager` service can be used to get the template definitions (created by the template definition providers). + +## See Also + +* [The source code of the sample application](https://github.com/abpframework/abp-samples/tree/master/TextTemplateDemo) developed and referred through this document. +* [Localization system](Localization.md). +* [Virtual File System](Virtual-File-System.md). diff --git a/docs/en/Text-Templating-Scriban.md b/docs/en/Text-Templating-Scriban.md new file mode 100644 index 0000000000..4d9be31dc8 --- /dev/null +++ b/docs/en/Text-Templating-Scriban.md @@ -0,0 +1,517 @@ +# Razor Integration + +## Installation + +It is suggested to use the [ABP CLI](CLI.md) to install this package. + +### Using the ABP CLI + +Open a command line window in the folder of the project (.csproj file) and type the following command: + +````bash +abp add-package Volo.Abp.TextTemplating.Scriban +```` + +### Manual Installation + +If you want to manually install; + +1. Add the [Volo.Abp.TextTemplating.Scriban](https://www.nuget.org/packages/Volo.Abp.TextTemplating.Scriban) NuGet package to your project: + +```` +Install-Package Volo.Abp.TextTemplating.Scriban +```` + +2. Add the `AbpTextTemplatingScribanModule` to the dependency list of your module: + +````csharp +[DependsOn( + //...other dependencies + typeof(AbpTextTemplatingScribanModule) //Add the new module dependency + )] +public class YourModule : AbpModule +{ +} +```` + +## Defining Templates + +Before rendering a template, you should define it. Create a class inheriting from the `TemplateDefinitionProvider` base class: + +````csharp +public class DemoTemplateDefinitionProvider : TemplateDefinitionProvider +{ + public override void Define(ITemplateDefinitionContext context) + { + context.Add( + new TemplateDefinition("Hello") //template name: "Hello" + .WithVirtualFilePath( + "/Demos/Hello/Hello.tpl", //template content path + isInlineLocalized: true + ) + ); + } +} +```` + +* `context` object is used to add new templates or get the templates defined by depended modules. Used `context.Add(...)` to define a new template. +* `TemplateDefinition` is the class represents a template. Each template must have a unique name (that will be used while you are rendering the template). +* `/Demos/Hello/Hello.tpl` is the path of the template file. +* `isInlineLocalized` is used to declare if you are using a single template for all languages (`true`) or different templates for each language (`false`). See the Localization section below for more. + +### The Template Content + +`WithVirtualFilePath` indicates that we are using the [Virtual File System](Virtual-File-System.md) to store the template content. Create a `Hello.tpl` file inside your project and mark it as "**embedded resource**" on the properties window: + +![hello-template](images/hello-template.png) + +Example `Hello.tpl` content is shown below: + +```` +Hello {%{{{model.name}}}%} :) +```` + +The [Virtual File System](Virtual-File-System.md) requires to add your files in the `ConfigureServices` method of your [module](Module-Development-Basics.md) class: + +````csharp +Configure(options => +{ + options.FileSets.AddEmbedded("TextTemplateDemo"); +}); +```` + +* `TextTemplateDemoModule` is the module class that you define your template in. +* `TextTemplateDemo` is the root namespace of your project. + +## Rendering the Template + +`ITemplateRenderer` service is used to render a template content. + +### Example: Rendering a Simple Template + +````csharp +public class HelloDemo : ITransientDependency +{ + private readonly ITemplateRenderer _templateRenderer; + + public HelloDemo(ITemplateRenderer templateRenderer) + { + _templateRenderer = templateRenderer; + } + + public async Task RunAsync() + { + var result = await _templateRenderer.RenderAsync( + "Hello", //the template name + new HelloModel + { + Name = "John" + } + ); + + Console.WriteLine(result); + } +} +```` + +* `HelloDemo` is a simple class that injects the `ITemplateRenderer` in its constructor and uses it inside the `RunAsync` method. +* `RenderAsync` gets two fundamental parameters: + * `templateName`: The name of the template to be rendered (`Hello` in this example). + * `model`: An object that is used as the `model` inside the template (a `HelloModel` object in this example). + +The result shown below for this example: + +````csharp +Hello John :) +```` + +### Anonymous Model + +While it is suggested to create model classes for the templates, it would be practical (and possible) to use anonymous objects for simple cases: + +````csharp +var result = await _templateRenderer.RenderAsync( + "Hello", + new + { + Name = "John" + } +); +```` + +In this case, we haven't created a model class, but created an anonymous object as the model. + +### PascalCase vs snake_case + +PascalCase property names (like `UserName`) is used as snake_case (like `user_name`) in the templates. + +## Localization + +It is possible to localize a template content based on the current culture. There are two types of localization options described in the following sections. + +### Inline localization + +Inline localization uses the [localization system](Localization.md) to localize texts inside templates. + +#### Example: Reset Password Link + +Assuming you need to send an email to a user to reset her/his password. Here, the template content: + +```` +{%{{{L "ResetMyPassword" model.name}}}%} +```` + +`L` function is used to localize the given key based on the current user culture. You need to define the `ResetMyPassword` key inside your localization file: + +````json +"ResetMyPasswordTitle": "Reset my password", +"ResetMyPassword": "Hi {0}, Click here to reset your password" +```` + +You also need to declare the localization resource to be used with this template, inside your template definition provider class: + +````csharp +context.Add( + new TemplateDefinition( + "PasswordReset", //Template name + typeof(DemoResource) //LOCALIZATION RESOURCE + ).WithVirtualFilePath( + "/Demos/PasswordReset/PasswordReset.tpl", //template content path + isInlineLocalized: true + ) +); +```` + +That's all. When you render this template like that: + +````csharp +var result = await _templateRenderer.RenderAsync( + "PasswordReset", //the template name + new PasswordResetModel + { + Name = "john", + Link = "https://abp.io/example-link?userId=123&token=ABC" + } +); +```` + +You will see the localized result: + +````csharp +Hi john, Click here to reset your password +```` + +> If you define the [default localization resource](Localization.md) for your application, then no need to declare the resource type for the template definition. + +### Multiple Contents Localization + +Instead of a single template that uses the localization system to localize the template, you may want to create different template files for each language. It can be needed if the template should be completely different for a specific culture rather than simple text localizations. + +#### Example: Welcome Email Template + +Assuming that you want to send a welcome email to your users, but want to define a completely different template based on the user culture. + +First, create a folder and put your templates inside it, like `en.tpl`, `tr.tpl`... one for each culture you support: + +![multiple-file-template](images/multiple-file-template.png) + +Then add your template definition in the template definition provider class: + +````csharp +context.Add( + new TemplateDefinition( + name: "WelcomeEmail", + defaultCultureName: "en" + ) + .WithVirtualFilePath( + "/Demos/WelcomeEmail/Templates", //template content folder + isInlineLocalized: false + ) +); +```` + +* Set **default culture name**, so it fallbacks to the default culture if there is no template for the desired culture. +* Specify **the template folder** rather than a single template file. +* Set `isInlineLocalized` to `false` for this case. + +That's all, you can render the template for the current culture: + +````csharp +var result = await _templateRenderer.RenderAsync("WelcomeEmail"); +```` + +> Skipped the modal for this example to keep it simple, but you can use models as just explained before. + +### Specify the Culture + +`ITemplateRenderer` service uses the current culture (`CultureInfo.CurrentUICulture`) if not specified. If you need, you can specify the culture as the `cultureName` parameter: + +````csharp +var result = await _templateRenderer.RenderAsync( + "WelcomeEmail", + cultureName: "en" +); +```` + +## Layout Templates + +Layout templates are used to create shared layouts among other templates. It is similar to the layout system in the ASP.NET Core MVC / Razor Pages. + +### Example: Email HTML Layout Template + +For example, you may want to create a single layout for all of your email templates. + +First, create a template file just like before: + +````xml + + + + + + + {%{{{content}}}%} + + +```` + +* A layout template must have a **{%{{{content}}}%}** part as a place holder for the rendered child content. + +The register your template in the template definition provider: + +````csharp +context.Add( + new TemplateDefinition( + "EmailLayout", + isLayout: true //SET isLayout! + ).WithVirtualFilePath( + "/Demos/EmailLayout/EmailLayout.tpl", + isInlineLocalized: true + ) +); +```` + +Now, you can use this template as the layout of any other template: + +````csharp +context.Add( + new TemplateDefinition( + name: "WelcomeEmail", + defaultCultureName: "en", + layout: "EmailLayout" //Set the LAYOUT + ).WithVirtualFilePath( + "/Demos/WelcomeEmail/Templates", + isInlineLocalized: false + ) +); +```` + +## Global Context + +ABP passes the `model` that can be used to access to the model inside the template. You can pass more global variables if you need. + +An example template content: + +```` +A global object value: {%{{{myGlobalObject}}}%} +```` + +This template assumes that that is a `myGlobalObject` object in the template rendering context. You can provide it like shown below: + +````csharp +var result = await _templateRenderer.RenderAsync( + "GlobalContextUsage", + globalContext: new Dictionary + { + {"myGlobalObject", "TEST VALUE"} + } +); +```` + +The rendering result will be: + +```` +A global object value: TEST VALUE +```` + +## Replacing the Existing Templates + +It is possible to replace a template defined by a module that used in your application. In this way, you can customize the templates based on your requirements without changing the module code. + +### Option-1: Using the Virtual File System + +The [Virtual File System](Virtual-File-System.md) allows you to override any file by placing the same file into the same path in your project. + +#### Example: Replace the Standard Email Layout Template + +ABP Framework provides an [email sending system](Emailing.md) that internally uses the text templating to render the email content. It defines a standard email layout template in the `/Volo/Abp/Emailing/Templates/Layout.tpl` path. The unique name of the template is `Abp.StandardEmailTemplates.Layout` and this string is defined as a constant on the `Volo.Abp.Emailing.Templates.StandardEmailTemplates` static class. + +Do the following steps to replace the template file with your own; + +**1)** Add a new file into the same location (`/Volo/Abp/Emailing/Templates/Layout.tpl`) in your project: + +![replace-email-layout](images/replace-email-layout.png) + +**2)** Prepare your email layout template: + +````html + + + + + + +

This my header

+ + {%{{{content}}}%} + +
+ This is my footer... +
+ + +```` + +This example simply adds a header and footer to the template and renders the content between them (see the *Layout Templates* section above to understand it). + +**3)** Configure the embedded resources in the `.csproj` file + +* Add [Microsoft.Extensions.FileProviders.Embedded](https://www.nuget.org/packages/Microsoft.Extensions.FileProviders.Embedded) NuGet package to the project. +* Add `true` into the `...` section of your `.csproj` file. +* Add the following code into your `.csproj` file: + +````xml + + + + +```` + +This makes the template files "embedded resource". + +**4)** Configure the virtual file system + +Configure the `AbpVirtualFileSystemOptions` in the `ConfigureServices` method of your [module](Module-Development-Basics.md) to add the embedded files into the virtual file system: + +```csharp +Configure(options => +{ + options.FileSets.AddEmbedded(); +}); +``` + +`BookStoreDomainModule` should be your module name, in this example code. + +> Be sure that your module (directly or indirectly) [depends on](Module-Development-Basics.md) the `AbpEmailingModule`. Because the VFS can override files based on the dependency order. + +Now, your template will be used when you want to render the email layout template. + +### Option-2: Using the Template Definition Provider + +You can create a template definition provider class that gets the email layout template and changes the virtual file path for the template. + +**Example: Use the `/MyTemplates/EmailLayout.tpl` file instead of the standard template** + +```csharp +using Volo.Abp.DependencyInjection; +using Volo.Abp.Emailing.Templates; +using Volo.Abp.TextTemplating; + +namespace MyProject +{ + public class MyTemplateDefinitionProvider + : TemplateDefinitionProvider, ITransientDependency + { + public override void Define(ITemplateDefinitionContext context) + { + var emailLayoutTemplate = context.GetOrNull(StandardEmailTemplates.Layout); + + emailLayoutTemplate + .WithVirtualFilePath( + "/MyTemplates/EmailLayout.tpl", + isInlineLocalized: true + ); + } + } +} +``` + +You should still add the file `/MyTemplates/EmailLayout.tpl` to the virtual file system as explained before. This approach allows you to locate templates in any folder instead of the folder defined by the depended module. + +Beside the template content, you can manipulate the template definition properties, like `DisplayName`, `Layout` or `LocalizationSource`. + +## Advanced Features + +This section covers some internals and more advanced usages of the text templating system. + +### Template Content Provider + +`ITemplateRenderer` is used to render the template, which is what you want for most of the cases. However, you can use the `ITemplateContentProvider` to get the raw (not rendered) template contents. + +> `ITemplateContentProvider` is internally used by the `ITemplateRenderer` to get the raw template contents. + +Example: + +````csharp +public class TemplateContentDemo : ITransientDependency +{ + private readonly ITemplateContentProvider _templateContentProvider; + + public TemplateContentDemo(ITemplateContentProvider templateContentProvider) + { + _templateContentProvider = templateContentProvider; + } + + public async Task RunAsync() + { + var result = await _templateContentProvider + .GetContentOrNullAsync("Hello"); + + Console.WriteLine(result); + } +} +```` + +The result will be the raw template content: + +```` +Hello {%{{{model.name}}}%} :) +```` + +* `GetContentOrNullAsync` returns `null` if no content defined for the requested template. +* It can get a `cultureName` parameter that is used if template has different files for different cultures (see Multiple Contents Localization section above). + +### Template Content Contributor + +`ITemplateContentProvider` service uses `ITemplateContentContributor` implementations to find template contents. There is a single pre-implemented content contributor, `VirtualFileTemplateContentContributor`, which gets template contents from the virtual file system as described above. + +You can implement the `ITemplateContentContributor` to read raw template contents from another source. + +Example: + +````csharp +public class MyTemplateContentProvider + : ITemplateContentContributor, ITransientDependency +{ + public async Task GetOrNullAsync(TemplateContentContributorContext context) + { + var templateName = context.TemplateDefinition.Name; + + //TODO: Try to find content from another source + return null; + } +} + +```` + +Return `null` if your source can not find the content, so `ITemplateContentProvider` fallbacks to the next contributor. + +### Template Definition Manager + +`ITemplateDefinitionManager` service can be used to get the template definitions (created by the template definition providers). + +## See Also + +* [The source code of the sample application](https://github.com/abpframework/abp-samples/tree/master/TextTemplateDemo) developed and referred through this document. +* [Localization system](Localization.md). +* [Virtual File System](Virtual-File-System.md). diff --git a/docs/en/Text-Templating.md b/docs/en/Text-Templating.md index bdea7cd00b..c9b03cd940 100644 --- a/docs/en/Text-Templating.md +++ b/docs/en/Text-Templating.md @@ -12,549 +12,21 @@ It is very similar to an ASP.NET Core Razor View (or Page): You can use the rendered output for any purpose, like sending emails or preparing some reports. -### Example - -Here, a simple template: - -```` -Hello {%{{{model.name}}}%} :) -```` - -You can define a class with a `Name` property to render this template: - -````csharp -public class HelloModel -{ - public string Name { get; set; } -} -```` - -If you render the template with a `HelloModel` with the `Name` is `John`, the rendered output is will be: - -```` -Hello John :) -```` - Template rendering engine is very powerful; -* It is based on the [Scriban](https://github.com/lunet-io/scriban) library, so it supports **conditional logics**, **loops** and much more. +* It supports **conditional logics**, **loops** and much more. * Template content **can be localized**. * You can define **layout templates** to be used as the layout while rendering other templates. * You can pass arbitrary objects to the template context (beside the model) for advanced scenarios. -### Source Code - -Get [the source code of the sample application](https://github.com/abpframework/abp-samples/tree/master/TextTemplateDemo) developed and referred through this document. - -## Installation - -It is suggested to use the [ABP CLI](CLI.md) to install this package. - -### Using the ABP CLI - -Open a command line window in the folder of the project (.csproj file) and type the following command: - -````bash -abp add-package Volo.Abp.TextTemplating -```` - -### Manual Installation - -If you want to manually install; - -1. Add the [Volo.Abp.TextTemplating](https://www.nuget.org/packages/Volo.Abp.TextTemplating) NuGet package to your project: - -```` -Install-Package Volo.Abp.TextTemplating -```` - -2. Add the `AbpTextTemplatingModule` to the dependency list of your module: - -````csharp -[DependsOn( - //...other dependencies - typeof(AbpTextTemplatingModule) //Add the new module dependency - )] -public class YourModule : AbpModule -{ -} -```` - -## Defining Templates - -Before rendering a template, you should define it. Create a class inheriting from the `TemplateDefinitionProvider` base class: - -````csharp -public class DemoTemplateDefinitionProvider : TemplateDefinitionProvider -{ - public override void Define(ITemplateDefinitionContext context) - { - context.Add( - new TemplateDefinition("Hello") //template name: "Hello" - .WithVirtualFilePath( - "/Demos/Hello/Hello.tpl", //template content path - isInlineLocalized: true - ) - ); - } -} -```` - -* `context` object is used to add new templates or get the templates defined by depended modules. Used `context.Add(...)` to define a new template. -* `TemplateDefinition` is the class represents a template. Each template must have a unique name (that will be used while you are rendering the template). -* `/Demos/Hello/Hello.tpl` is the path of the template file. -* `isInlineLocalized` is used to declare if you are using a single template for all languages (`true`) or different templates for each language (`false`). See the Localization section below for more. - -### The Template Content - -`WithVirtualFilePath` indicates that we are using the [Virtual File System](Virtual-File-System.md) to store the template content. Create a `Hello.tpl` file inside your project and mark it as "**embedded resource**" on the properties window: - -![hello-template](images/hello-template.png) - -Example `Hello.tpl` content is shown below: - -```` -Hello {%{{{model.name}}}%} :) -```` - -The [Virtual File System](Virtual-File-System.md) requires to add your files in the `ConfigureServices` method of your [module](Module-Development-Basics.md) class: - -````csharp -Configure(options => -{ - options.FileSets.AddEmbedded("TextTemplateDemo"); -}); -```` - -* `TextTemplateDemoModule` is the module class that you define your template in. -* `TextTemplateDemo` is the root namespace of your project. - -## Rendering the Template - -`ITemplateRenderer` service is used to render a template content. - -### Example: Rendering a Simple Template - -````csharp -public class HelloDemo : ITransientDependency -{ - private readonly ITemplateRenderer _templateRenderer; - - public HelloDemo(ITemplateRenderer templateRenderer) - { - _templateRenderer = templateRenderer; - } - - public async Task RunAsync() - { - var result = await _templateRenderer.RenderAsync( - "Hello", //the template name - new HelloModel - { - Name = "John" - } - ); - - Console.WriteLine(result); - } -} -```` - -* `HelloDemo` is a simple class that injects the `ITemplateRenderer` in its constructor and uses it inside the `RunAsync` method. -* `RenderAsync` gets two fundamental parameters: - * `templateName`: The name of the template to be rendered (`Hello` in this example). - * `model`: An object that is used as the `model` inside the template (a `HelloModel` object in this example). - -The result shown below for this example: - -````csharp -Hello John :) -```` - -### Anonymous Model - -While it is suggested to create model classes for the templates, it would be practical (and possible) to use anonymous objects for simple cases: - -````csharp -var result = await _templateRenderer.RenderAsync( - "Hello", - new - { - Name = "John" - } -); -```` - -In this case, we haven't created a model class, but created an anonymous object as the model. - -### PascalCase vs snake_case - -PascalCase property names (like `UserName`) is used as snake_case (like `user_name`) in the templates. - -## Localization - -It is possible to localize a template content based on the current culture. There are two types of localization options described in the following sections. - -### Inline localization - -Inline localization uses the [localization system](Localization.md) to localize texts inside templates. - -#### Example: Reset Password Link - -Assuming you need to send an email to a user to reset her/his password. Here, the template content: - -```` -{%{{{L "ResetMyPassword" model.name}}}%} -```` - -`L` function is used to localize the given key based on the current user culture. You need to define the `ResetMyPassword` key inside your localization file: - -````json -"ResetMyPasswordTitle": "Reset my password", -"ResetMyPassword": "Hi {0}, Click here to reset your password" -```` - -You also need to declare the localization resource to be used with this template, inside your template definition provider class: - -````csharp -context.Add( - new TemplateDefinition( - "PasswordReset", //Template name - typeof(DemoResource) //LOCALIZATION RESOURCE - ).WithVirtualFilePath( - "/Demos/PasswordReset/PasswordReset.tpl", //template content path - isInlineLocalized: true - ) -); -```` - -That's all. When you render this template like that: - -````csharp -var result = await _templateRenderer.RenderAsync( - "PasswordReset", //the template name - new PasswordResetModel - { - Name = "john", - Link = "https://abp.io/example-link?userId=123&token=ABC" - } -); -```` - -You will see the localized result: - -````csharp -Hi john, Click here to reset your password -```` - -> If you define the [default localization resource](Localization.md) for your application, then no need to declare the resource type for the template definition. - -### Multiple Contents Localization - -Instead of a single template that uses the localization system to localize the template, you may want to create different template files for each language. It can be needed if the template should be completely different for a specific culture rather than simple text localizations. - -#### Example: Welcome Email Template - -Assuming that you want to send a welcome email to your users, but want to define a completely different template based on the user culture. - -First, create a folder and put your templates inside it, like `en.tpl`, `tr.tpl`... one for each culture you support: - -![multiple-file-template](images/multiple-file-template.png) - -Then add your template definition in the template definition provider class: - -````csharp -context.Add( - new TemplateDefinition( - name: "WelcomeEmail", - defaultCultureName: "en" - ) - .WithVirtualFilePath( - "/Demos/WelcomeEmail/Templates", //template content folder - isInlineLocalized: false - ) -); -```` - -* Set **default culture name**, so it fallbacks to the default culture if there is no template for the desired culture. -* Specify **the template folder** rather than a single template file. -* Set `isInlineLocalized` to `false` for this case. - -That's all, you can render the template for the current culture: - -````csharp -var result = await _templateRenderer.RenderAsync("WelcomeEmail"); -```` - -> Skipped the modal for this example to keep it simple, but you can use models as just explained before. +ABP Framework provides two types of engines; -### Specify the Culture +* **[Razor](Text-Templating-Razor.md)** +* **[Scriban](Text-Templating-Scriban.md)** -`ITemplateRenderer` service uses the current culture (`CultureInfo.CurrentUICulture`) if not specified. If you need, you can specify the culture as the `cultureName` parameter: +## Source Code -````csharp -var result = await _templateRenderer.RenderAsync( - "WelcomeEmail", - cultureName: "en" -); -```` - -## Layout Templates - -Layout templates are used to create shared layouts among other templates. It is similar to the layout system in the ASP.NET Core MVC / Razor Pages. - -### Example: Email HTML Layout Template - -For example, you may want to create a single layout for all of your email templates. - -First, create a template file just like before: - -````xml - - - - - - - {%{{{content}}}%} - - -```` - -* A layout template must have a **{%{{{content}}}%}** part as a place holder for the rendered child content. - -The register your template in the template definition provider: - -````csharp -context.Add( - new TemplateDefinition( - "EmailLayout", - isLayout: true //SET isLayout! - ).WithVirtualFilePath( - "/Demos/EmailLayout/EmailLayout.tpl", - isInlineLocalized: true - ) -); -```` - -Now, you can use this template as the layout of any other template: - -````csharp -context.Add( - new TemplateDefinition( - name: "WelcomeEmail", - defaultCultureName: "en", - layout: "EmailLayout" //Set the LAYOUT - ).WithVirtualFilePath( - "/Demos/WelcomeEmail/Templates", - isInlineLocalized: false - ) -); -```` - -## Global Context - -ABP passes the `model` that can be used to access to the model inside the template. You can pass more global variables if you need. - -An example template content: - -```` -A global object value: {%{{{myGlobalObject}}}%} -```` - -This template assumes that that is a `myGlobalObject` object in the template rendering context. You can provide it like shown below: - -````csharp -var result = await _templateRenderer.RenderAsync( - "GlobalContextUsage", - globalContext: new Dictionary - { - {"myGlobalObject", "TEST VALUE"} - } -); -```` - -The rendering result will be: - -```` -A global object value: TEST VALUE -```` - -## Replacing the Existing Templates - -It is possible to replace a template defined by a module that used in your application. In this way, you can customize the templates based on your requirements without changing the module code. - -### Option-1: Using the Virtual File System - -The [Virtual File System](Virtual-File-System.md) allows you to override any file by placing the same file into the same path in your project. - -#### Example: Replace the Standard Email Layout Template - -ABP Framework provides an [email sending system](Emailing.md) that internally uses the text templating to render the email content. It defines a standard email layout template in the `/Volo/Abp/Emailing/Templates/Layout.tpl` path. The unique name of the template is `Abp.StandardEmailTemplates.Layout` and this string is defined as a constant on the `Volo.Abp.Emailing.Templates.StandardEmailTemplates` static class. - -Do the following steps to replace the template file with your own; - -**1)** Add a new file into the same location (`/Volo/Abp/Emailing/Templates/Layout.tpl`) in your project: - -![replace-email-layout](images/replace-email-layout.png) - -**2)** Prepare your email layout template: - -````html - - - - - - -

This my header

- - {%{{{content}}}%} - -
- This is my footer... -
- - -```` - -This example simply adds a header and footer to the template and renders the content between them (see the *Layout Templates* section above to understand it). - -**3)** Configure the embedded resources in the `.csproj` file - -* Add [Microsoft.Extensions.FileProviders.Embedded](https://www.nuget.org/packages/Microsoft.Extensions.FileProviders.Embedded) NuGet package to the project. -* Add `true` into the `...` section of your `.csproj` file. -* Add the following code into your `.csproj` file: - -````xml - - - - -```` - -This makes the template files "embedded resource". - -**4)** Configure the virtual file system - -Configure the `AbpVirtualFileSystemOptions` in the `ConfigureServices` method of your [module](Module-Development-Basics.md) to add the embedded files into the virtual file system: - -```csharp -Configure(options => -{ - options.FileSets.AddEmbedded(); -}); -``` - -`BookStoreDomainModule` should be your module name, in this example code. - -> Be sure that your module (directly or indirectly) [depends on](Module-Development-Basics.md) the `AbpEmailingModule`. Because the VFS can override files based on the dependency order. - -Now, your template will be used when you want to render the email layout template. - -### Option-2: Using the Template Definition Provider - -You can create a template definition provider class that gets the email layout template and changes the virtual file path for the template. - -**Example: Use the `/MyTemplates/EmailLayout.tpl` file instead of the standard template** - -```csharp -using Volo.Abp.DependencyInjection; -using Volo.Abp.Emailing.Templates; -using Volo.Abp.TextTemplating; - -namespace MyProject -{ - public class MyTemplateDefinitionProvider - : TemplateDefinitionProvider, ITransientDependency - { - public override void Define(ITemplateDefinitionContext context) - { - var emailLayoutTemplate = context.GetOrNull(StandardEmailTemplates.Layout); - - emailLayoutTemplate - .WithVirtualFilePath( - "/MyTemplates/EmailLayout.tpl", - isInlineLocalized: true - ); - } - } -} -``` - -You should still add the file `/MyTemplates/EmailLayout.tpl` to the virtual file system as explained before. This approach allows you to locate templates in any folder instead of the folder defined by the depended module. - -Beside the template content, you can manipulate the template definition properties, like `DisplayName`, `Layout` or `LocalizationSource`. - -## Advanced Features - -This section covers some internals and more advanced usages of the text templating system. - -### Template Content Provider - -`ITemplateRenderer` is used to render the template, which is what you want for most of the cases. However, you can use the `ITemplateContentProvider` to get the raw (not rendered) template contents. - -> `ITemplateContentProvider` is internally used by the `ITemplateRenderer` to get the raw template contents. - -Example: - -````csharp -public class TemplateContentDemo : ITransientDependency -{ - private readonly ITemplateContentProvider _templateContentProvider; - - public TemplateContentDemo(ITemplateContentProvider templateContentProvider) - { - _templateContentProvider = templateContentProvider; - } - - public async Task RunAsync() - { - var result = await _templateContentProvider - .GetContentOrNullAsync("Hello"); - - Console.WriteLine(result); - } -} -```` - -The result will be the raw template content: - -```` -Hello {%{{{model.name}}}%} :) -```` - -* `GetContentOrNullAsync` returns `null` if no content defined for the requested template. -* It can get a `cultureName` parameter that is used if template has different files for different cultures (see Multiple Contents Localization section above). - -### Template Content Contributor - -`ITemplateContentProvider` service uses `ITemplateContentContributor` implementations to find template contents. There is a single pre-implemented content contributor, `VirtualFileTemplateContentContributor`, which gets template contents from the virtual file system as described above. - -You can implement the `ITemplateContentContributor` to read raw template contents from another source. - -Example: - -````csharp -public class MyTemplateContentProvider - : ITemplateContentContributor, ITransientDependency -{ - public async Task GetOrNullAsync(TemplateContentContributorContext context) - { - var templateName = context.TemplateDefinition.Name; - - //TODO: Try to find content from another source - return null; - } -} - -```` - -Return `null` if your source can not find the content, so `ITemplateContentProvider` fallbacks to the next contributor. - -### Template Definition Manager - -`ITemplateDefinitionManager` service can be used to get the template definitions (created by the template definition providers). +Get [the source code of the sample application](https://github.com/abpframework/abp-samples/tree/master/TextTemplateDemo) developed and referred through this document. ## See Also diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index efca73a484..8be0210381 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -326,7 +326,17 @@ }, { "text": "Text Templating", - "path": "Text-Templating.md" + "path": "Text-Templating.md", + "items": [ + { + "text": "Razor Integration", + "path": "Text-Templating-Razor.md" + }, + { + "text": "Scriban Integration", + "path": "Text-Templating-Scriban.md" + } + ] }, { "text": "Timing", From ba02106bf6ecdf72ff8ae8a1a85fc16903d8dab2 Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 5 Apr 2021 16:13:13 +0800 Subject: [PATCH 3/7] Depend on AbpTextTemplatingScribanModule. --- .../Volo/Abp/TextTemplating/AbpTextTemplatingModule.cs | 4 ++++ 1 file changed, 4 insertions(+) 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 6b0ad6fb11..d5817d0d33 100644 --- a/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/AbpTextTemplatingModule.cs +++ b/framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/AbpTextTemplatingModule.cs @@ -1,7 +1,11 @@ using Volo.Abp.Modularity; +using Volo.Abp.TextTemplating.Scriban; namespace Volo.Abp.TextTemplating { + [DependsOn( + typeof(AbpTextTemplatingScribanModule) + )] public class AbpTextTemplatingModule : AbpModule { From 1ef61d56e3ec0fbabc95d6d112f4805ac4af8ea4 Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 5 Apr 2021 16:32:48 +0800 Subject: [PATCH 4/7] Add images. --- docs/en/Text-Templating-Razor.md | 10 +++++----- docs/en/images/hello-template-razor.png | Bin 0 -> 51361 bytes .../en/images/multiple-file-template-razor.png | Bin 0 -> 49452 bytes docs/en/images/replace-email-layout-razor.png | Bin 0 -> 104744 bytes 4 files changed, 5 insertions(+), 5 deletions(-) create mode 100644 docs/en/images/hello-template-razor.png create mode 100644 docs/en/images/multiple-file-template-razor.png create mode 100644 docs/en/images/replace-email-layout-razor.png diff --git a/docs/en/Text-Templating-Razor.md b/docs/en/Text-Templating-Razor.md index 6c4f9080c6..5bb00b4e82 100644 --- a/docs/en/Text-Templating-Razor.md +++ b/docs/en/Text-Templating-Razor.md @@ -162,7 +162,7 @@ Inline localization uses the [localization system](Localization.md) to localize Assuming you need to send an email to a user to reset her/his password. Here, the model/template content: -```` +````csharp namespace ResetMyPasswordModelNamespace { public class ResetMyPasswordModel @@ -174,7 +174,7 @@ namespace ResetMyPasswordModelNamespace } ```` -```` +````html @inherits Volo.Abp.TextTemplating.Razor.RazorTemplatePageBase @Localizer["ResetMyPassword", Model.Name] ```` @@ -215,7 +215,7 @@ var result = await _templateRenderer.RenderAsync( You will see the localized result: -````csharp +````html Hi john, Click here to reset your password ```` @@ -281,7 +281,7 @@ For example, you may want to create a single layout for all of your email templa First, create a template file just like before: -````csharp +````html @inherits Volo.Abp.TextTemplating.Razor.RazorTemplatePageBase @@ -331,7 +331,7 @@ ABP passes the `model` that can be used to access to the model inside the templa An example template content: -````csharp +````html @inherits Volo.Abp.TextTemplating.Razor.RazorTemplatePageBase A global object value: @GlobalContext["myGlobalObject"] ```` diff --git a/docs/en/images/hello-template-razor.png b/docs/en/images/hello-template-razor.png new file mode 100644 index 0000000000000000000000000000000000000000..1e0e39fcecf5585d5c824ad6c4880986895d6cbc GIT binary patch literal 51361 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�I6<3 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

N3-)b~OZN+`Oh^wEBjEOqJ-@VJ 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 literal 0 HcmV?d00001 From 3e4ccc3a9a9e7f8e21ddbb861e7830502a0484a8 Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 5 Apr 2021 17:15:32 +0800 Subject: [PATCH 5/7] Add AbpCompiledViewProviderOptions --- .../Razor/AbpCompiledViewProviderOptions.cs | 15 ++++++++++ ...r.cs => AbpRazorTemplateCSharpCompiler.cs} | 8 ++--- ... AbpRazorTemplateCSharpCompilerOptions.cs} | 4 +-- ...r.cs => DefaultAbpCompiledViewProvider.cs} | 29 ++++++++++++++----- ...=> DefaultAbpRazorProjectEngineFactory.cs} | 2 +- ...rovider.cs => IAbpCompiledViewProvider.cs} | 2 +- ...ry.cs => IAbpRazorProjectEngineFactory.cs} | 2 +- .../Razor/RazorTemplateRenderer.cs | 8 ++--- .../Razor/RazorTextTemplatingTestModule.cs | 2 +- 9 files changed, 50 insertions(+), 22 deletions(-) create mode 100644 framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/AbpCompiledViewProviderOptions.cs rename framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/{CSharpCompiler.cs => AbpRazorTemplateCSharpCompiler.cs} (92%) rename framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/{CSharpCompilerOptions.cs => AbpRazorTemplateCSharpCompilerOptions.cs} (71%) rename framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/{DefaultCompiledViewProvider.cs => DefaultAbpCompiledViewProvider.cs} (66%) rename framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/{DefaultRazorProjectEngineFactory.cs => DefaultAbpRazorProjectEngineFactory.cs} (85%) rename framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/{ICompiledViewProvider.cs => IAbpCompiledViewProvider.cs} (80%) rename framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/{IRazorProjectEngineFactory.cs => IAbpRazorProjectEngineFactory.cs} (82%) diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/AbpCompiledViewProviderOptions.cs b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/AbpCompiledViewProviderOptions.cs new file mode 100644 index 0000000000..6da3e8b443 --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/AbpCompiledViewProviderOptions.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using Microsoft.CodeAnalysis; + +namespace Volo.Abp.TextTemplating.Razor +{ + public class AbpCompiledViewProviderOptions + { + public Dictionary> TemplateReferences { get; } + + public AbpCompiledViewProviderOptions() + { + TemplateReferences = new Dictionary>(); + } + } +} 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/AbpRazorTemplateCSharpCompiler.cs similarity index 92% rename from framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/CSharpCompiler.cs rename to framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/AbpRazorTemplateCSharpCompiler.cs index 5c6bc2d190..55b0d10f17 100644 --- a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/CSharpCompiler.cs +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/AbpRazorTemplateCSharpCompiler.cs @@ -12,11 +12,11 @@ using Volo.Abp.DependencyInjection; namespace Volo.Abp.TextTemplating.Razor { - public class CSharpCompiler : ISingletonDependency + public class AbpRazorTemplateCSharpCompiler : ISingletonDependency { - protected CSharpCompilerOptions Options { get; } + protected AbpRazorTemplateCSharpCompilerOptions Options { get; } - public CSharpCompiler(IOptions options) + public AbpRazorTemplateCSharpCompiler(IOptions options) { Options = options.Value; } @@ -35,7 +35,7 @@ namespace Volo.Abp.TextTemplating.Razor Assembly.Load("Microsoft.Extensions.Localization"), Assembly.Load("Microsoft.Extensions.Localization.Abstractions"), - typeof(CSharpCompiler).Assembly + typeof(AbpRazorTemplateCSharpCompiler).Assembly } .Select(x => MetadataReference.CreateFromFile(x.Location)) .ToImmutableList(); 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/AbpRazorTemplateCSharpCompilerOptions.cs similarity index 71% rename from framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/CSharpCompilerOptions.cs rename to framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/AbpRazorTemplateCSharpCompilerOptions.cs index d419b83fca..20c1e391e0 100644 --- a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/CSharpCompilerOptions.cs +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/AbpRazorTemplateCSharpCompilerOptions.cs @@ -3,11 +3,11 @@ using Microsoft.CodeAnalysis; namespace Volo.Abp.TextTemplating.Razor { - public class CSharpCompilerOptions + public class AbpRazorTemplateCSharpCompilerOptions { public List References { get; } - public CSharpCompilerOptions() + public AbpRazorTemplateCSharpCompilerOptions() { 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/DefaultAbpCompiledViewProvider.cs similarity index 66% rename from framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultCompiledViewProvider.cs rename to framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultAbpCompiledViewProvider.cs index ff954b3b99..c743252456 100644 --- a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultCompiledViewProvider.cs +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultAbpCompiledViewProvider.cs @@ -2,28 +2,35 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Reflection; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.CodeAnalysis; +using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; namespace Volo.Abp.TextTemplating.Razor { - public class DefaultCompiledViewProvider : ICompiledViewProvider, ITransientDependency + public class DefaultAbpCompiledViewProvider : IAbpCompiledViewProvider, ITransientDependency { private static readonly ConcurrentDictionary CachedAssembles = new ConcurrentDictionary(); - private readonly CSharpCompiler _cSharpCompiler; - private readonly IRazorProjectEngineFactory _razorProjectEngineFactory; + private readonly AbpCompiledViewProviderOptions _options; + private readonly AbpRazorTemplateCSharpCompiler _razorTemplateCSharpCompiler; + private readonly IAbpRazorProjectEngineFactory _razorProjectEngineFactory; private readonly ITemplateContentProvider _templateContentProvider; - public DefaultCompiledViewProvider( - IRazorProjectEngineFactory razorProjectEngineFactory, - CSharpCompiler cSharpCompiler, + public DefaultAbpCompiledViewProvider( + IOptions options, + IAbpRazorProjectEngineFactory razorProjectEngineFactory, + AbpRazorTemplateCSharpCompiler razorTemplateCSharpCompiler, ITemplateContentProvider templateContentProvider) { + _options = options.Value; + _razorProjectEngineFactory = razorProjectEngineFactory; - _cSharpCompiler = cSharpCompiler; + _razorTemplateCSharpCompiler = razorTemplateCSharpCompiler; _templateContentProvider = templateContentProvider; } @@ -58,7 +65,13 @@ namespace Volo.Abp.TextTemplating.Razor var cSharpDocument = codeDocument.GetCSharpDocument(); - return _cSharpCompiler.CreateAssembly(cSharpDocument.GeneratedCode, templateDefinition.Name); + var templateReferences = _options.TemplateReferences + .GetOrDefault(templateDefinition.Name) + ?.Select(x => x) + .Cast() + .ToList(); + + return _razorTemplateCSharpCompiler.CreateAssembly(cSharpDocument.GeneratedCode, templateDefinition.Name, templateReferences); } } } 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/DefaultAbpRazorProjectEngineFactory.cs similarity index 85% rename from framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultRazorProjectEngineFactory.cs rename to framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultAbpRazorProjectEngineFactory.cs index c402a26bb2..eb6d851f49 100644 --- a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultRazorProjectEngineFactory.cs +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultAbpRazorProjectEngineFactory.cs @@ -5,7 +5,7 @@ using Volo.Abp.DependencyInjection; namespace Volo.Abp.TextTemplating.Razor { - public class DefaultRazorProjectEngineFactory : IRazorProjectEngineFactory, ITransientDependency + public class DefaultAbpRazorProjectEngineFactory : IAbpRazorProjectEngineFactory, ITransientDependency { public virtual async Task CreateAsync(Action configure = null) { 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/IAbpCompiledViewProvider.cs similarity index 80% rename from framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/ICompiledViewProvider.cs rename to framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/IAbpCompiledViewProvider.cs index a0bc2043aa..ba5e96d2fa 100644 --- a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/ICompiledViewProvider.cs +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/IAbpCompiledViewProvider.cs @@ -3,7 +3,7 @@ using System.Threading.Tasks; namespace Volo.Abp.TextTemplating.Razor { - public interface ICompiledViewProvider + public interface IAbpCompiledViewProvider { 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/IAbpRazorProjectEngineFactory.cs similarity index 82% rename from framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/IRazorProjectEngineFactory.cs rename to framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/IAbpRazorProjectEngineFactory.cs index 138a78b72f..c96b171f59 100644 --- a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/IRazorProjectEngineFactory.cs +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/IAbpRazorProjectEngineFactory.cs @@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Razor.Language; namespace Volo.Abp.TextTemplating.Razor { - public interface IRazorProjectEngineFactory + public interface IAbpRazorProjectEngineFactory { Task CreateAsync(Action configure = null); } 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 index 6ec926b398..db06e67d4a 100644 --- 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 @@ -16,20 +16,20 @@ namespace Volo.Abp.TextTemplating.Razor public class RazorTemplateRenderer : ITemplateRenderer, ITransientDependency { private readonly IServiceScopeFactory _serviceScopeFactory; - private readonly ICompiledViewProvider _compiledViewProvider; + private readonly IAbpCompiledViewProvider _abpCompiledViewProvider; private readonly ITemplateDefinitionManager _templateDefinitionManager; private readonly IStringLocalizerFactory _stringLocalizerFactory; public RazorTemplateRenderer( IServiceScopeFactory serviceScopeFactory, - ICompiledViewProvider compiledViewProvider, + IAbpCompiledViewProvider abpCompiledViewProvider, ITemplateDefinitionManager templateDefinitionManager, IStringLocalizerFactory stringLocalizerFactory) { _serviceScopeFactory = serviceScopeFactory; _templateDefinitionManager = templateDefinitionManager; _stringLocalizerFactory = stringLocalizerFactory; - _compiledViewProvider = compiledViewProvider; + _abpCompiledViewProvider = abpCompiledViewProvider; } public virtual async Task RenderAsync( @@ -115,7 +115,7 @@ namespace Volo.Abp.TextTemplating.Razor Dictionary globalContext, object model = null) { - var assembly = await _compiledViewProvider.GetAssemblyAsync(templateDefinition); + var assembly = await _abpCompiledViewProvider.GetAssemblyAsync(templateDefinition); var templateType = assembly.GetType(AbpRazorTemplateConsts.TypeName); var template = (IRazorTemplatePage) Activator.CreateInstance(templateType); 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 index 6832f88dfa..df2f8b3b3d 100644 --- 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 @@ -17,7 +17,7 @@ namespace Volo.Abp.TextTemplating.Razor options.FileSets.AddEmbedded("Volo.Abp.TextTemplating.Razor"); }); - Configure(options => + Configure(options => { options.References.Add(MetadataReference.CreateFromFile(typeof(RazorTextTemplatingTestModule).Assembly.Location)); }); From ae86bf229482a3fd01a93d6d48606120ad1a2815 Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 5 Apr 2021 17:46:15 +0800 Subject: [PATCH 6/7] Add Custom_TemplateReferences_Test. --- .../AbpCompiledViewProviderOptions_Tests.cs | 48 +++++++++++++++++++ .../RazorTestTemplateDefinitionProvider.cs | 6 ++- .../SampleTemplates/RazorTestTemplates.cs | 7 +++ .../Razor/SampleTemplates/TestTemplate.cshtml | 6 +++ 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/AbpCompiledViewProviderOptions_Tests.cs create mode 100644 framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/RazorTestTemplates.cs create mode 100644 framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/TestTemplate.cshtml diff --git a/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/AbpCompiledViewProviderOptions_Tests.cs b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/AbpCompiledViewProviderOptions_Tests.cs new file mode 100644 index 0000000000..9f4cd3ecaa --- /dev/null +++ b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/AbpCompiledViewProviderOptions_Tests.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Volo.Abp.TextTemplating.Razor.SampleTemplates; +using Xunit; + +namespace Volo.Abp.TextTemplating.Razor +{ + public class AbpCompiledViewProviderOptions_Tests : TemplateDefinitionTests + { + private readonly IAbpCompiledViewProvider _compiledViewProvider; + private readonly ITemplateDefinitionManager _templateDefinitionManager; + + public AbpCompiledViewProviderOptions_Tests() + { + _templateDefinitionManager = GetRequiredService(); + _compiledViewProvider = GetRequiredService(); + } + + protected override void AfterAddApplication(IServiceCollection services) + { + services.Configure(options => + { + options.TemplateReferences.Add(RazorTestTemplates.TestTemplate, new List() + { + Assembly.Load("Microsoft.Extensions.Logging.Abstractions") + } + .Select(x => MetadataReference.CreateFromFile(x.Location)) + .ToList()); + }); + base.AfterAddApplication(services); + } + + [Fact] + public async Task Custom_TemplateReferences_Test() + { + var templateDefinition = _templateDefinitionManager.GetOrNull(RazorTestTemplates.TestTemplate); + + var assembly = await _compiledViewProvider.GetAssemblyAsync(templateDefinition); + + assembly.GetReferencedAssemblies().ShouldContain(x => x.Name == "Microsoft.Extensions.Logging.Abstractions"); + } + } +} 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 index 5fdd0a786b..3bb1d7f831 100644 --- 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 @@ -1,4 +1,6 @@ -namespace Volo.Abp.TextTemplating.Razor +using Volo.Abp.TextTemplating.Razor.SampleTemplates; + +namespace Volo.Abp.TextTemplating.Razor { public class RazorTestTemplateDefinitionProvider : TemplateDefinitionProvider { @@ -15,6 +17,8 @@ context.GetOrNull(TestTemplates.ShowDecimalNumber)? .WithVirtualFilePath("/SampleTemplates/ShowDecimalNumber.cshtml", true); + + context.Add(new TemplateDefinition(RazorTestTemplates.TestTemplate).WithVirtualFilePath("/SampleTemplates/TestTemplate.cshtml", true)); } } } diff --git a/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/RazorTestTemplates.cs b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/RazorTestTemplates.cs new file mode 100644 index 0000000000..3fa87f7d90 --- /dev/null +++ b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/RazorTestTemplates.cs @@ -0,0 +1,7 @@ +namespace Volo.Abp.TextTemplating.Razor.SampleTemplates +{ + public static class RazorTestTemplates + { + public const string TestTemplate = "TestTemplate"; + } +} diff --git a/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/TestTemplate.cshtml b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/TestTemplate.cshtml new file mode 100644 index 0000000000..3de93e1e40 --- /dev/null +++ b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/TestTemplate.cshtml @@ -0,0 +1,6 @@ +@using Microsoft.Extensions.DependencyInjection +@using Microsoft.Extensions.Logging +@inherits Volo.Abp.TextTemplating.Razor.RazorTemplatePageBase +@{ + var loggerFactory = ServiceProvider.GetService(); +} From 58140c37ab6a1ac6ea1c0ed9c980fe9ad2899751 Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 5 Apr 2021 17:58:25 +0800 Subject: [PATCH 7/7] Update Text-Templating-Razor.md --- docs/en/Text-Templating-Razor.md | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/docs/en/Text-Templating-Razor.md b/docs/en/Text-Templating-Razor.md index 5bb00b4e82..700d262b9b 100644 --- a/docs/en/Text-Templating-Razor.md +++ b/docs/en/Text-Templating-Razor.md @@ -1,5 +1,9 @@ # Razor Integration + +The Razor template is a standard C# class, so you can freely use the functions of C#, such as `dependency injection`, using `LINQ`, custom methods, and even using `Repository`. + + ## Installation It is suggested to use the [ABP CLI](CLI.md) to install this package. @@ -41,13 +45,34 @@ You need to add the `MetadataReference` of the type used in the template to `CSh ````csharp public override void ConfigureServices(ServiceConfigurationContext context) { - Configure(options => + Configure(options => { options.References.Add(MetadataReference.CreateFromFile(typeof(YourModule).Assembly.Location)); }); } ```` +## Add MetadataReference for a template. + +You can add some `MetadataReference` to the template + +````csharp +public override void ConfigureServices(ServiceConfigurationContext context) +{ + services.Configure(options => + { + //Hello is template name. + options.TemplateReferences.Add("Hello", new List() + { + Assembly.Load("Microsoft.Extensions.Logging.Abstractions"), + Assembly.Load("Microsoft.Extensions.Logging") + } + .Select(x => MetadataReference.CreateFromFile(x.Location)) + .ToList()); + }); +} +```` + ## Defining Templates Before rendering a template, you should define it. Create a class inheriting from the `TemplateDefinitionProvider` base class: @@ -73,6 +98,11 @@ public class DemoTemplateDefinitionProvider : TemplateDefinitionProvider * `/Demos/Hello/Hello.cshtml` is the path of the template file. * `isInlineLocalized` is used to declare if you are using a single template for all languages (`true`) or different templates for each language (`false`). See the Localization section below for more. +### The Template Base + +Every `cshtml` template page needs to inherit `RazorTemplatePageBase` or `RazorTemplatePageBase`. +There are some useful properties in the base class that can be used in templates. eg: `Localizer`, `ServiceProvider`. + ### The Template Content `WithVirtualFilePath` indicates that we are using the [Virtual File System](Virtual-File-System.md) to store the template content. Create a `Hello.cshtml` file inside your project and mark it as "**embedded resource**" on the properties window: