Browse Source

Razor engine support for text templating

Resolve #8373
pull/8392/head
maliming 6 years ago
parent
commit
6d38c9f500
  1. 35
      framework/Volo.Abp.sln
  2. 3
      framework/src/Volo.Abp.TextTemplating.Abstractions/FodyWeavers.xml
  3. 30
      framework/src/Volo.Abp.TextTemplating.Abstractions/FodyWeavers.xsd
  4. 16
      framework/src/Volo.Abp.TextTemplating.Abstractions/Volo.Abp.TextTemplating.Abstractions.csproj
  5. 46
      framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/AbpTextTemplatingAbstractionsModule.cs
  6. 0
      framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/AbpTextTemplatingOptions.cs
  7. 0
      framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/ITemplateContentContributor.cs
  8. 0
      framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/ITemplateContentProvider.cs
  9. 0
      framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/ITemplateDefinitionContext.cs
  10. 0
      framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/ITemplateDefinitionManager.cs
  11. 0
      framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/ITemplateDefinitionProvider.cs
  12. 0
      framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/ITemplateRenderer.cs
  13. 0
      framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateContentContributorContext.cs
  14. 0
      framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateContentProvider.cs
  15. 0
      framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateDefinition.cs
  16. 0
      framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateDefinitionContext.cs
  17. 0
      framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateDefinitionExtensions.cs
  18. 0
      framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateDefinitionManager.cs
  19. 0
      framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateDefinitionProvider.cs
  20. 0
      framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/FileInfoLocalizedTemplateContentReader.cs
  21. 0
      framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/ILocalizedTemplateContentReader.cs
  22. 0
      framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/ILocalizedTemplateContentReaderFactory.cs
  23. 3
      framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/LocalizedTemplateContentReaderFactory.cs
  24. 0
      framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/NullLocalizedTemplateContentReader.cs
  25. 0
      framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/VirtualFileTemplateContentContributor.cs
  26. 8
      framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/VirtualFolderLocalizedTemplateContentReader.cs
  27. 3
      framework/src/Volo.Abp.TextTemplating.Razor/FodyWeavers.xml
  28. 30
      framework/src/Volo.Abp.TextTemplating.Razor/FodyWeavers.xsd
  29. 21
      framework/src/Volo.Abp.TextTemplating.Razor/Volo.Abp.TextTemplating.Razor.csproj
  30. 9
      framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/AbpRazorTemplateConsts.cs
  31. 12
      framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/AbpTextTemplatingRazorModule.cs
  32. 107
      framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/CSharpCompiler.cs
  33. 15
      framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/CSharpCompilerOptions.cs
  34. 64
      framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultCompiledViewProvider.cs
  35. 20
      framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultRazorProjectEngineFactory.cs
  36. 30
      framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/EmptyProjectFileSystem.cs
  37. 10
      framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/ICompiledViewProvider.cs
  38. 11
      framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/IRazorProjectEngineFactory.cs
  39. 34
      framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/IRazorTemplatePage.cs
  40. 28
      framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/NotFoundProjectItem.cs
  41. 177
      framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/RazorTemplatePageBase.cs
  42. 168
      framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/RazorTemplateRenderer.cs
  43. 3
      framework/src/Volo.Abp.TextTemplating.Scriban/FodyWeavers.xml
  44. 30
      framework/src/Volo.Abp.TextTemplating.Scriban/FodyWeavers.xsd
  45. 19
      framework/src/Volo.Abp.TextTemplating.Scriban/Volo.Abp.TextTemplating.Scriban.csproj
  46. 12
      framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/AbpTextTemplatingScribanModule.cs
  47. 6
      framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/ScribanTemplateLocalizer.cs
  48. 12
      framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/ScribanTemplateRenderer.cs
  49. 13
      framework/src/Volo.Abp.TextTemplating/Volo.Abp.TextTemplating.csproj
  50. 39
      framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/AbpTextTemplatingModule.cs
  51. 23
      framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo.Abp.TextTemplating.Razor.Tests.csproj
  52. 26
      framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorLocalizedTemplateContentReaderFactory_Tests.cs
  53. 7
      framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorTemplateDefinitionTests.cs
  54. 145
      framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorTemplateRenderer_Tests.cs
  55. 20
      framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorTestTemplateDefinitionProvider.cs
  56. 26
      framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorTextTemplatingTestModule.cs
  57. 23
      framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorVirtualFileTemplateContributor_Tests.cs
  58. 2
      framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/ForgotPasswordEmail.cshtml
  59. 2
      framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/ShowDecimalNumber.cshtml
  60. 2
      framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/TestTemplateLayout1.cshtml
  61. 2
      framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/WelcomeEmail/en.cshtml
  62. 2
      framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/WelcomeEmail/tr.cshtml
  63. 23
      framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo.Abp.TextTemplating.Scriban.Tests.csproj
  64. 0
      framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/SampleTemplates/ForgotPasswordEmail.tpl
  65. 0
      framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/SampleTemplates/ShowDecimalNumber.tpl
  66. 0
      framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/SampleTemplates/TestTemplateLayout1.tpl
  67. 0
      framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/SampleTemplates/WelcomeEmail/en.tpl
  68. 0
      framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/SampleTemplates/WelcomeEmail/tr.tpl
  69. 20
      framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanLocalizedTemplateContentReaderFactory_Tests.cs
  70. 7
      framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanTemplateDefinitionTests.cs
  71. 8
      framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanTemplateRenderer_Tests.cs
  72. 20
      framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanTestTemplateDefinitionProvider.cs
  73. 20
      framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanTextTemplatingTestModule.cs
  74. 14
      framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/ScribanVirtualFileTemplateContributor_Tests.cs
  75. 5
      framework/test/Volo.Abp.TextTemplating.Tests/Volo.Abp.TextTemplating.Tests.csproj
  76. 4
      framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/AbpTextTemplatingOptions_Tests.cs
  77. 6
      framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/AbpTextTemplatingTestBase.cs
  78. 2
      framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/AbpTextTemplatingTestModule.cs
  79. 20
      framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TemplateDefinitionTests.cs
  80. 10
      framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TestTemplateDefinitionProvider.cs
  81. 29
      framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/VirtualFiles/LocalizedTemplateContentReaderFactory_Tests.cs
  82. 35
      framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/VirtualFiles/VirtualFileTemplateContributor_Tests.cs
  83. 3
      nupkg/common.ps1

35
framework/Volo.Abp.sln

@ -383,6 +383,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Compone
EndProject 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}" 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 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 Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU 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}.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.ActiveCfg = Release|Any CPU
{E9CE58DB-0789-4D18-8B63-474F7D7B14B4}.Release|Any CPU.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -1334,6 +1364,11 @@ Global
{863C18F9-2407-49F9-9ADC-F6229AF3B385} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {863C18F9-2407-49F9-9ADC-F6229AF3B385} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{B4B6B7DE-9798-4007-B1DF-7EE7929E392A} = {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} {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 EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5} SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5}

3
framework/src/Volo.Abp.TextTemplating.Abstractions/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
framework/src/Volo.Abp.TextTemplating.Abstractions/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

16
framework/src/Volo.Abp.TextTemplating.Abstractions/Volo.Abp.TextTemplating.Abstractions.csproj

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Localization.Abstractions\Volo.Abp.Localization.Abstractions.csproj" />
<ProjectReference Include="..\Volo.Abp.VirtualFileSystem\Volo.Abp.VirtualFileSystem.csproj" />
</ItemGroup>
</Project>

46
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<Type>();
var contentContributors = new List<Type>();
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<AbpTextTemplatingOptions>(options =>
{
options.DefinitionProviders.AddIfNotContains(definitionProviders);
options.ContentContributors.AddIfNotContains(contentContributors);
});
}
}
}

0
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/AbpTextTemplatingOptions.cs → framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/AbpTextTemplatingOptions.cs

0
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/ITemplateContentContributor.cs → framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/ITemplateContentContributor.cs

0
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/ITemplateContentProvider.cs → framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/ITemplateContentProvider.cs

0
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/ITemplateDefinitionContext.cs → framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/ITemplateDefinitionContext.cs

0
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/ITemplateDefinitionManager.cs → framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/ITemplateDefinitionManager.cs

0
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/ITemplateDefinitionProvider.cs → framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/ITemplateDefinitionProvider.cs

0
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/ITemplateRenderer.cs → framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/ITemplateRenderer.cs

0
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateContentContributorContext.cs → framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateContentContributorContext.cs

0
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateContentProvider.cs → framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateContentProvider.cs

0
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateDefinition.cs → framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateDefinition.cs

0
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateDefinitionContext.cs → framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateDefinitionContext.cs

0
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateDefinitionExtensions.cs → framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateDefinitionExtensions.cs

0
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateDefinitionManager.cs → framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateDefinitionManager.cs

0
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateDefinitionProvider.cs → framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/TemplateDefinitionProvider.cs

0
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/FileInfoLocalizedTemplateContentReader.cs → framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/FileInfoLocalizedTemplateContentReader.cs

0
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/ILocalizedTemplateContentReader.cs → framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/ILocalizedTemplateContentReader.cs

0
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/ILocalizedTemplateContentReaderFactory.cs → framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/ILocalizedTemplateContentReaderFactory.cs

3
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/LocalizedTemplateContentReaderFactory.cs → framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/LocalizedTemplateContentReaderFactory.cs

@ -64,7 +64,8 @@ namespace Volo.Abp.TextTemplating.VirtualFiles
if (fileInfo.IsDirectory) if (fileInfo.IsDirectory)
{ {
var folderReader = new VirtualFolderLocalizedTemplateContentReader(); //TODO: Configure file extensions.
var folderReader = new VirtualFolderLocalizedTemplateContentReader(new[] {".tpl", ".cshtml"});
await folderReader.ReadContentsAsync(VirtualFileProvider, virtualPath); await folderReader.ReadContentsAsync(VirtualFileProvider, virtualPath);
return folderReader; return folderReader;
} }

0
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/NullLocalizedTemplateContentReader.cs → framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/NullLocalizedTemplateContentReader.cs

0
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/VirtualFileTemplateContentContributor.cs → framework/src/Volo.Abp.TextTemplating.Abstractions/Volo/Abp/TextTemplating/VirtualFiles/VirtualFileTemplateContentContributor.cs

8
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/VirtualFolderLocalizedTemplateContentReader.cs → 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 public class VirtualFolderLocalizedTemplateContentReader : ILocalizedTemplateContentReader
{ {
private Dictionary<string, string> _dictionary; private Dictionary<string, string> _dictionary;
private readonly string[] _fileExtension;
public VirtualFolderLocalizedTemplateContentReader(string[] fileExtension)
{
_fileExtension = fileExtension;
}
public async Task ReadContentsAsync( public async Task ReadContentsAsync(
IVirtualFileProvider virtualFileProvider, IVirtualFileProvider virtualFileProvider,
@ -29,7 +35,7 @@ namespace Volo.Abp.TextTemplating.VirtualFiles
continue; continue;
} }
_dictionary.Add(file.Name.RemovePostFix(".tpl"), await file.ReadAsStringAsync()); _dictionary.Add(file.Name.RemovePostFix(_fileExtension), await file.ReadAsStringAsync());
} }
} }

3
framework/src/Volo.Abp.TextTemplating.Razor/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
framework/src/Volo.Abp.TextTemplating.Razor/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

21
framework/src/Volo.Abp.TextTemplating.Razor/Volo.Abp.TextTemplating.Razor.csproj

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.TextTemplating.Abstractions\Volo.Abp.TextTemplating.Abstractions.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.9.0" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Language" Version="$(MicrosoftPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="$(MicrosoftPackageVersion)" />
</ItemGroup>
</Project>

9
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;
}
}

12
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
{
}
}

107
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<CSharpCompilerOptions> options)
{
Options = options.Value;
}
private static IEnumerable<PortableExecutableReference> DefaultReferences => new List<Assembly>()
{
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<MetadataReference> 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<string, ReportDiagnostic>
{
{"CS1701", ReportDiagnostic.Suppress}, // Binding redirects
{"CS1702", ReportDiagnostic.Suppress},
{"CS1705", ReportDiagnostic.Suppress}
});
return csharpCompilationOptions.WithOptimizationLevel(OptimizationLevel.Release);
}
}
}

15
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<PortableExecutableReference> References { get; }
public CSharpCompilerOptions()
{
References = new List<PortableExecutableReference>();
}
}
}

64
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<string, Assembly> CachedAssembles = new ConcurrentDictionary<string, Assembly>();
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<Assembly> GetAssemblyAsync(TemplateDefinition templateDefinition)
{
async Task<Assembly> 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<Stream> 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<RazorSourceDocument>(), new List<TagHelperDescriptor>());
var cSharpDocument = codeDocument.GetCSharpDocument();
return _cSharpCompiler.CreateAssembly(cSharpDocument.GeneratedCode, templateDefinition.Name);
}
}
}

20
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<RazorProjectEngine> CreateAsync(Action<RazorProjectEngineBuilder> configure = null)
{
return RazorProjectEngine.Create(await CreateRazorConfigurationAsync(), EmptyProjectFileSystem.Empty, configure);
}
protected virtual Task<RazorConfiguration> CreateRazorConfigurationAsync()
{
return Task.FromResult(RazorConfiguration.Default);
}
}
}

30
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<RazorProjectItem> EnumerateItems(string basePath)
{
NormalizeAndEnsureValidPath(basePath);
return Enumerable.Empty<RazorProjectItem>();
}
[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);
}
}
}

10
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<Assembly> GetAssemblyAsync(TemplateDefinition templateDefinition);
}
}

11
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<RazorProjectEngine> CreateAsync(Action<RazorProjectEngineBuilder> configure = null);
}
}

34
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<TModel> : 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<string, object> GlobalContext { get; set; }
string Body { get; set; }
Task ExecuteAsync();
Task<string> GetOutputAsync();
}
}

28
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();
}
}

177
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<TModel> : RazorTemplatePageBase, IRazorTemplatePage<TModel>
{
public TModel Model { get; set; }
}
public abstract class RazorTemplatePageBase : IRazorTemplatePage
{
public Dictionary<string, object> 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<string> 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; }
}
}
}

168
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<string> RenderAsync(
[NotNull] string templateName,
[CanBeNull] object model = null,
[CanBeNull] string cultureName = null,
[CanBeNull] Dictionary<string, object> globalContext = null)
{
Check.NotNullOrWhiteSpace(templateName, nameof(templateName));
if (globalContext == null)
{
globalContext = new Dictionary<string, object>();
}
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<string> RenderInternalAsync(
string templateName,
string body,
Dictionary<string, object> 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<string> RenderSingleTemplateAsync(
TemplateDefinition templateDefinition,
string body,
Dictionary<string, object> globalContext,
object model = null)
{
return await RenderTemplateContentWithRazorAsync(
templateDefinition,
body,
globalContext,
model
);
}
protected virtual async Task<string> RenderTemplateContentWithRazorAsync(
TemplateDefinition templateDefinition,
string body,
Dictionary<string, object> 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<HtmlEncoder>();
template.JavaScriptEncoder = scope.ServiceProvider.GetService<JavaScriptEncoder>();
template.UrlEncoder = scope.ServiceProvider.GetService<UrlEncoder>();
template.Body = body;
template.GlobalContext = globalContext;
await template.ExecuteAsync();
return await template.GetOutputAsync();
}
}
private void SetModel<TModel>(IRazorTemplatePage razorTemplatePage, object model = null)
{
if (razorTemplatePage is IRazorTemplatePage<TModel> razorTemplatePageWithModel)
{
razorTemplatePageWithModel.Model = (TModel)model;
}
}
private IStringLocalizer GetLocalizerOrNull(TemplateDefinition templateDefinition)
{
if (templateDefinition.LocalizationResource != null)
{
return _stringLocalizerFactory.Create(templateDefinition.LocalizationResource);
}
return _stringLocalizerFactory.CreateDefaultOrNull();
}
}
}

3
framework/src/Volo.Abp.TextTemplating.Scriban/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
framework/src/Volo.Abp.TextTemplating.Scriban/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

19
framework/src/Volo.Abp.TextTemplating.Scriban/Volo.Abp.TextTemplating.Scriban.csproj

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.TextTemplating.Abstractions\Volo.Abp.TextTemplating.Abstractions.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Scriban" Version="3.6.0" />
</ItemGroup>
</Project>

12
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
{
}
}

6
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateLocalizer.cs → framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/ScribanTemplateLocalizer.cs

@ -7,13 +7,13 @@ using Scriban;
using Scriban.Runtime; using Scriban.Runtime;
using Scriban.Syntax; using Scriban.Syntax;
namespace Volo.Abp.TextTemplating namespace Volo.Abp.TextTemplating.Scriban
{ {
public class TemplateLocalizer : IScriptCustomFunction public class ScribanTemplateLocalizer : IScriptCustomFunction
{ {
private readonly IStringLocalizer _localizer; private readonly IStringLocalizer _localizer;
public TemplateLocalizer(IStringLocalizer localizer) public ScribanTemplateLocalizer(IStringLocalizer localizer)
{ {
_localizer = localizer; _localizer = localizer;
} }

12
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateRenderer.cs → 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 System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.Localization; using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using Scriban; using Scriban;
using Scriban.Runtime; using Scriban.Runtime;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Localization; 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 ITemplateContentProvider _templateContentProvider;
private readonly ITemplateDefinitionManager _templateDefinitionManager; private readonly ITemplateDefinitionManager _templateDefinitionManager;
private readonly IStringLocalizerFactory _stringLocalizerFactory; private readonly IStringLocalizerFactory _stringLocalizerFactory;
public TemplateRenderer( public ScribanTemplateRenderer(
ITemplateContentProvider templateContentProvider, ITemplateContentProvider templateContentProvider,
ITemplateDefinitionManager templateDefinitionManager, ITemplateDefinitionManager templateDefinitionManager,
IStringLocalizerFactory stringLocalizerFactory) IStringLocalizerFactory stringLocalizerFactory)
@ -140,7 +138,7 @@ namespace Volo.Abp.TextTemplating
var localizer = GetLocalizerOrNull(templateDefinition); var localizer = GetLocalizerOrNull(templateDefinition);
if (localizer != null) if (localizer != null)
{ {
scriptObject.SetValue("L", new TemplateLocalizer(localizer), true); scriptObject.SetValue("L", new ScribanTemplateLocalizer(localizer), true);
} }
context.PushGlobal(scriptObject); context.PushGlobal(scriptObject);

13
framework/src/Volo.Abp.TextTemplating/Volo.Abp.TextTemplating.csproj

@ -5,22 +5,11 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Volo.Abp.TextTemplating</AssemblyName>
<PackageId>Volo.Abp.TextTemplating</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace /> <RootNamespace />
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Scriban" Version="3.6.0" /> <ProjectReference Include="..\Volo.Abp.TextTemplating.Scriban\Volo.Abp.TextTemplating.Scriban.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Localization.Abstractions\Volo.Abp.Localization.Abstractions.csproj" />
<ProjectReference Include="..\Volo.Abp.VirtualFileSystem\Volo.Abp.VirtualFileSystem.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

39
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/AbpTextTemplatingModule.cs

@ -1,46 +1,9 @@
using System; using Volo.Abp.Modularity;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.TextTemplating namespace Volo.Abp.TextTemplating
{ {
[DependsOn(
typeof(AbpVirtualFileSystemModule),
typeof(AbpLocalizationAbstractionsModule)
)]
public class AbpTextTemplatingModule : AbpModule public class AbpTextTemplatingModule : AbpModule
{ {
public override void PreConfigureServices(ServiceConfigurationContext context)
{
AutoAddProvidersAndContributors(context.Services);
}
private static void AutoAddProvidersAndContributors(IServiceCollection services)
{
var definitionProviders = new List<Type>();
var contentContributors = new List<Type>();
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<AbpTextTemplatingOptions>(options =>
{
options.DefinitionProviders.AddIfNotContains(definitionProviders);
options.ContentContributors.AddIfNotContains(contentContributors);
});
}
} }
} }

23
framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo.Abp.TextTemplating.Razor.Tests.csproj

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.test.props" />
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="Volo\Abp\TextTemplating\Razor\SampleTemplates\**\*.cshtml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
<None Remove="Volo\Abp\TextTemplating\Razor\SampleTemplates\**\*.cshtml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Volo.Abp.TextTemplating.Razor\Volo.Abp.TextTemplating.Razor.csproj" />
<ProjectReference Include="..\Volo.Abp.TextTemplating.Tests\Volo.Abp.TextTemplating.Tests.csproj" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPackageVersion)" />
</ItemGroup>
</Project>

26
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<RazorTextTemplatingTestModule>
{
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<Volo.Abp.TextTemplating.Razor.RazorTemplateRenderer_Tests.WelcomeEmailModel>" +
Environment.NewLine +
"Welcome @Model.Name to the abp.io!";
WelcomeEmailTurkishContent = "@inherits Volo.Abp.TextTemplating.Razor.RazorTemplatePageBase<Volo.Abp.TextTemplating.Razor.RazorTemplateRenderer_Tests.WelcomeEmailModel>" +
Environment.NewLine +
"Merhaba @Model.Name, abp.io'ya hoşgeldiniz!";
}
}
}

7
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<RazorTextTemplatingTestModule>
{
}
}

145
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<RazorTextTemplatingTestModule>
{
private readonly ITemplateRenderer _templateRenderer;
public RazorTemplateRenderer_Tests()
{
_templateRenderer = GetRequiredService<ITemplateRenderer>();
}
[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;
}
}
}
}

20
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);
}
}
}

26
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<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<RazorTextTemplatingTestModule>("Volo.Abp.TextTemplating.Razor");
});
Configure<CSharpCompilerOptions>(options =>
{
options.References.Add(MetadataReference.CreateFromFile(typeof(RazorTextTemplatingTestModule).Assembly.Location));
});
}
}
}

23
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<RazorTextTemplatingTestModule>
{
public RazorVirtualFileTemplateContributor_Tests()
{
WelcomeEmailEnglishContent = "@inherits Volo.Abp.TextTemplating.Razor.RazorTemplatePageBase<Volo.Abp.TextTemplating.Razor.RazorTemplateRenderer_Tests.WelcomeEmailModel>" +
Environment.NewLine +
"Welcome @Model.Name to the abp.io!";
WelcomeEmailTurkishContent = "@inherits Volo.Abp.TextTemplating.Razor.RazorTemplatePageBase<Volo.Abp.TextTemplating.Razor.RazorTemplateRenderer_Tests.WelcomeEmailModel>" +
Environment.NewLine +
"Merhaba @Model.Name, abp.io'ya hoşgeldiniz!";
ForgotPasswordEmailEnglishContent = "@inherits Volo.Abp.TextTemplating.Razor.RazorTemplatePageBase<Volo.Abp.TextTemplating.Razor.RazorTemplateRenderer_Tests.ForgotPasswordEmailModel>" +
Environment.NewLine +
"@Localizer[\"HelloText\", Model.Name], @Localizer[\"HowAreYou\"]. Please click to the following link to get an email to reset your password!";
}
}
}

2
framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/ForgotPasswordEmail.cshtml

@ -0,0 +1,2 @@
@inherits Volo.Abp.TextTemplating.Razor.RazorTemplatePageBase<Volo.Abp.TextTemplating.Razor.RazorTemplateRenderer_Tests.ForgotPasswordEmailModel>
@Localizer["HelloText", Model.Name], @Localizer["HowAreYou"]. Please click to the following link to get an email to reset your password!

2
framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/SampleTemplates/ShowDecimalNumber.cshtml

@ -0,0 +1,2 @@
@inherits Volo.Abp.TextTemplating.Razor.RazorTemplatePageBase<Volo.Abp.TextTemplating.Razor.RazorTemplateRenderer_Tests.ShowDecimalNumberModel>
@Model.Amount

2
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*

2
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<Volo.Abp.TextTemplating.Razor.RazorTemplateRenderer_Tests.WelcomeEmailModel>
Welcome @Model.Name to the abp.io!

2
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<Volo.Abp.TextTemplating.Razor.RazorTemplateRenderer_Tests.WelcomeEmailModel>
Merhaba @Model.Name, abp.io'ya hoşgeldiniz!

23
framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo.Abp.TextTemplating.Scriban.Tests.csproj

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.test.props" />
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="Volo\Abp\TextTemplating\Scriban\SampleTemplates\**\*.tpl">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
<None Remove="Volo\Abp\TextTemplating\Scriban\SampleTemplates\**\*.tpl" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Volo.Abp.TextTemplating.Scriban\Volo.Abp.TextTemplating.Scriban.csproj" />
<ProjectReference Include="..\Volo.Abp.TextTemplating.Tests\Volo.Abp.TextTemplating.Tests.csproj" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPackageVersion)" />
</ItemGroup>
</Project>

0
framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/SampleTemplates/ForgotPasswordEmail.tpl → framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/SampleTemplates/ForgotPasswordEmail.tpl

0
framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/SampleTemplates/ShowDecimalNumber.tpl → framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/SampleTemplates/ShowDecimalNumber.tpl

0
framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/SampleTemplates/TestTemplateLayout1.tpl → framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/SampleTemplates/TestTemplateLayout1.tpl

0
framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/SampleTemplates/WelcomeEmail/en.tpl → framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/SampleTemplates/WelcomeEmail/en.tpl

0
framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/SampleTemplates/WelcomeEmail/tr.tpl → framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/SampleTemplates/WelcomeEmail/tr.tpl

20
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<ScribanTextTemplatingTestModule>
{
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!";
}
}
}

7
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<ScribanTextTemplatingTestModule>
{
}
}

8
framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TemplateRenderer_Tests.cs → 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 Shouldly;
using Xunit; using Xunit;
namespace Volo.Abp.TextTemplating namespace Volo.Abp.TextTemplating.Scriban
{ {
public class TemplateRenderer_Tests : AbpTextTemplatingTestBase public class ScribanTemplateRenderer_Tests : AbpTextTemplatingTestBase<ScribanTextTemplatingTestModule>
{ {
private readonly ITemplateRenderer _templateRenderer; private readonly ITemplateRenderer _templateRenderer;
public TemplateRenderer_Tests() public ScribanTemplateRenderer_Tests()
{ {
_templateRenderer = GetRequiredService<ITemplateRenderer>(); _templateRenderer = GetRequiredService<ITemplateRenderer>();
} }
@ -91,7 +91,7 @@ namespace Volo.Abp.TextTemplating
cultureName: "tr" cultureName: "tr"
)).ShouldBe("*BEGIN*Merhaba John, nasılsın?. Please click to the following link to get an email to reset your password!*END*"); )).ShouldBe("*BEGIN*Merhaba John, nasılsın?. Please click to the following link to get an email to reset your password!*END*");
} }
[Fact] [Fact]
public async Task Should_Get_Localized_Numbers() public async Task Should_Get_Localized_Numbers()
{ {

20
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);
}
}
}

20
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<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<ScribanTextTemplatingTestModule>("Volo.Abp.TextTemplating.Scriban");
});
}
}
}

14
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<ScribanTextTemplatingTestModule>
{
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!";
}
}
}

5
framework/test/Volo.Abp.TextTemplating.Tests/Volo.Abp.TextTemplating.Tests.csproj

@ -10,15 +10,12 @@
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="Volo\Abp\TextTemplating\Localization\**\*.json" /> <EmbeddedResource Include="Volo\Abp\TextTemplating\Localization\**\*.json" />
<None Remove="Volo\Abp\TextTemplating\Localization\**\*.json" /> <None Remove="Volo\Abp\TextTemplating\Localization\**\*.json" />
<EmbeddedResource Include="Volo\Abp\TextTemplating\SampleTemplates\**\*.tpl">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Volo.Abp.Localization\Volo.Abp.Localization.csproj" /> <ProjectReference Include="..\..\src\Volo.Abp.Localization\Volo.Abp.Localization.csproj" />
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" /> <ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.TextTemplating\Volo.Abp.TextTemplating.csproj" /> <ProjectReference Include="..\..\src\Volo.Abp.TextTemplating.Abstractions\Volo.Abp.TextTemplating.Abstractions.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" /> <ProjectReference Include="..\..\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPackageVersion)" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPackageVersion)" />
</ItemGroup> </ItemGroup>

4
framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/AbpTextTemplatingOptions_Tests.cs

@ -4,7 +4,7 @@ using Xunit;
namespace Volo.Abp.TextTemplating namespace Volo.Abp.TextTemplating
{ {
public class AbpTextTemplatingOptions_Tests : AbpTextTemplatingTestBase public class AbpTextTemplatingOptions_Tests : AbpTextTemplatingTestBase<AbpTextTemplatingTestModule>
{ {
private readonly AbpTextTemplatingOptions _options; private readonly AbpTextTemplatingOptions _options;
@ -21,4 +21,4 @@ namespace Volo.Abp.TextTemplating
.ShouldContain(typeof(TestTemplateDefinitionProvider)); .ShouldContain(typeof(TestTemplateDefinitionProvider));
} }
} }
} }

6
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 namespace Volo.Abp.TextTemplating
{ {
public abstract class AbpTextTemplatingTestBase : AbpIntegratedTest<AbpTextTemplatingTestModule> public abstract class AbpTextTemplatingTestBase<TStartupModule> : AbpIntegratedTest<TStartupModule>
where TStartupModule : IAbpModule
{ {
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{ {

2
framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/AbpTextTemplatingTestModule.cs

@ -7,7 +7,7 @@ using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.TextTemplating namespace Volo.Abp.TextTemplating
{ {
[DependsOn( [DependsOn(
typeof(AbpTextTemplatingModule), typeof(AbpTextTemplatingAbstractionsModule),
typeof(AbpTestBaseModule), typeof(AbpTestBaseModule),
typeof(AbpAutofacModule), typeof(AbpAutofacModule),
typeof(AbpLocalizationModule) typeof(AbpLocalizationModule)

20
framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TemplateDefinitionTests.cs

@ -1,25 +1,27 @@
using Shouldly; using Shouldly;
using Volo.Abp.Modularity;
using Xunit; using Xunit;
namespace Volo.Abp.TextTemplating namespace Volo.Abp.TextTemplating
{ {
public class TemplateDefinitionTests : AbpTextTemplatingTestBase public abstract class TemplateDefinitionTests<TStartupModule> : AbpTextTemplatingTestBase<TStartupModule>
where TStartupModule : IAbpModule
{ {
private readonly ITemplateDefinitionManager _templateDefinitionManager; protected readonly ITemplateDefinitionManager TemplateDefinitionManager;
public TemplateDefinitionTests() protected TemplateDefinitionTests()
{ {
_templateDefinitionManager = GetRequiredService<ITemplateDefinitionManager>(); TemplateDefinitionManager = GetRequiredService<ITemplateDefinitionManager>();
} }
[Fact] [Fact]
public void Should_Retrieve_Template_Definition_By_Name() 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.Name.ShouldBe(TestTemplates.WelcomeEmail);
welcomeEmailTemplate.IsInlineLocalized.ShouldBeFalse(); welcomeEmailTemplate.IsInlineLocalized.ShouldBeFalse();
var forgotPasswordEmailTemplate = _templateDefinitionManager.Get(TestTemplates.ForgotPasswordEmail); var forgotPasswordEmailTemplate = TemplateDefinitionManager.Get(TestTemplates.ForgotPasswordEmail);
forgotPasswordEmailTemplate.Name.ShouldBe(TestTemplates.ForgotPasswordEmail); forgotPasswordEmailTemplate.Name.ShouldBe(TestTemplates.ForgotPasswordEmail);
forgotPasswordEmailTemplate.IsInlineLocalized.ShouldBeTrue(); forgotPasswordEmailTemplate.IsInlineLocalized.ShouldBeTrue();
} }
@ -27,15 +29,15 @@ namespace Volo.Abp.TextTemplating
[Fact] [Fact]
public void Should_Get_Null_If_Template_Not_Found() public void Should_Get_Null_If_Template_Not_Found()
{ {
var definition = _templateDefinitionManager.GetOrNull("undefined-template"); var definition = TemplateDefinitionManager.GetOrNull("undefined-template");
definition.ShouldBeNull(); definition.ShouldBeNull();
} }
[Fact] [Fact]
public void Should_Retrieve_All_Template_Definitions() public void Should_Retrieve_All_Template_Definitions()
{ {
var definitions = _templateDefinitionManager.GetAll(); var definitions = TemplateDefinitionManager.GetAll();
definitions.Count.ShouldBeGreaterThan(1); definitions.Count.ShouldBeGreaterThan(1);
} }
} }
} }

10
framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TestTemplateDefinitionProvider.cs

@ -10,7 +10,7 @@ namespace Volo.Abp.TextTemplating
new TemplateDefinition( new TemplateDefinition(
TestTemplates.WelcomeEmail, TestTemplates.WelcomeEmail,
defaultCultureName: "en" defaultCultureName: "en"
).WithVirtualFilePath("/SampleTemplates/WelcomeEmail", false) )
); );
context.Add( context.Add(
@ -18,22 +18,22 @@ namespace Volo.Abp.TextTemplating
TestTemplates.ForgotPasswordEmail, TestTemplates.ForgotPasswordEmail,
localizationResource: typeof(TestLocalizationSource), localizationResource: typeof(TestLocalizationSource),
layout: TestTemplates.TestTemplateLayout1 layout: TestTemplates.TestTemplateLayout1
).WithVirtualFilePath("/SampleTemplates/ForgotPasswordEmail.tpl", true) )
); );
context.Add( context.Add(
new TemplateDefinition( new TemplateDefinition(
TestTemplates.TestTemplateLayout1, TestTemplates.TestTemplateLayout1,
isLayout: true isLayout: true
).WithVirtualFilePath("/SampleTemplates/TestTemplateLayout1.tpl", true) )
); );
context.Add( context.Add(
new TemplateDefinition( new TemplateDefinition(
TestTemplates.ShowDecimalNumber, TestTemplates.ShowDecimalNumber,
localizationResource: typeof(TestLocalizationSource), localizationResource: typeof(TestLocalizationSource),
layout: TestTemplates.TestTemplateLayout1 layout: TestTemplates.TestTemplateLayout1
).WithVirtualFilePath("/SampleTemplates/ShowDecimalNumber.tpl", true) )
); );
} }
} }

29
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.FileProviders;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using Shouldly; using Shouldly;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem; using Volo.Abp.VirtualFileSystem;
using Xunit; using Xunit;
namespace Volo.Abp.TextTemplating.VirtualFiles namespace Volo.Abp.TextTemplating.VirtualFiles
{ {
public class LocalizedTemplateContentReaderFactory_Tests: AbpTextTemplatingTestBase public abstract class LocalizedTemplateContentReaderFactory_Tests<TStartupModule> : AbpTextTemplatingTestBase<TStartupModule>
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<ITemplateDefinitionManager>(); TemplateDefinitionManager = GetRequiredService<ITemplateDefinitionManager>();
} }
[Fact] [Fact]
public async Task Create_Should_Work_With_PhysicalFileProvider() public async Task Create_Should_Work_With_PhysicalFileProvider()
{ {
var localizedTemplateContentReaderFactory = new LocalizedTemplateContentReaderFactory( var reader = await LocalizedTemplateContentReaderFactory.CreateAsync(TemplateDefinitionManager.Get(TestTemplates.WelcomeEmail));
new PhysicalFileVirtualFileProvider(
new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(),
"Volo", "Abp", "TextTemplating"))));
var reader = await localizedTemplateContentReaderFactory.CreateAsync(_templateDefinitionManager.Get(TestTemplates.WelcomeEmail)); reader.GetContentOrNull("en").ShouldBe(WelcomeEmailEnglishContent);
reader.GetContentOrNull("tr").ShouldBe(WelcomeEmailTurkishContent);
reader.GetContentOrNull("en").ShouldBe("Welcome {{model.name}} to the abp.io!");
reader.GetContentOrNull("tr").ShouldBe("Merhaba {{model.name}}, abp.io'ya hoşgeldiniz!");
} }
class PhysicalFileVirtualFileProvider : IVirtualFileProvider public class PhysicalFileVirtualFileProvider : IVirtualFileProvider
{ {
private readonly PhysicalFileProvider _physicalFileProvider; private readonly PhysicalFileProvider _physicalFileProvider;

35
framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/VirtualFiles/VirtualFileTemplateContributor_Tests.cs

@ -1,45 +1,50 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Shouldly; using Shouldly;
using Volo.Abp.Modularity;
using Xunit; using Xunit;
namespace Volo.Abp.TextTemplating.VirtualFiles namespace Volo.Abp.TextTemplating.VirtualFiles
{ {
public class VirtualFileTemplateContributor_Tests : AbpTextTemplatingTestBase public abstract class VirtualFileTemplateContributor_Tests<TStartupModule> : AbpTextTemplatingTestBase<TStartupModule>
where TStartupModule : IAbpModule
{ {
private readonly ITemplateDefinitionManager _templateDefinitionManager; protected readonly ITemplateDefinitionManager TemplateDefinitionManager;
private readonly VirtualFileTemplateContentContributor _virtualFileTemplateContentContributor; protected readonly VirtualFileTemplateContentContributor VirtualFileTemplateContentContributor;
protected string WelcomeEmailEnglishContent;
protected string WelcomeEmailTurkishContent;
protected string ForgotPasswordEmailEnglishContent;
public VirtualFileTemplateContributor_Tests() protected VirtualFileTemplateContributor_Tests()
{ {
_templateDefinitionManager = GetRequiredService<ITemplateDefinitionManager>(); TemplateDefinitionManager = GetRequiredService<ITemplateDefinitionManager>();
_virtualFileTemplateContentContributor = GetRequiredService<VirtualFileTemplateContentContributor>(); VirtualFileTemplateContentContributor = GetRequiredService<VirtualFileTemplateContentContributor>();
} }
[Fact] [Fact]
public async Task Should_Get_Localized_Content_By_Culture() public async Task Should_Get_Localized_Content_By_Culture()
{ {
(await _virtualFileTemplateContentContributor.GetOrNullAsync( (await VirtualFileTemplateContentContributor.GetOrNullAsync(
new TemplateContentContributorContext(_templateDefinitionManager.Get(TestTemplates.WelcomeEmail), new TemplateContentContributorContext(TemplateDefinitionManager.Get(TestTemplates.WelcomeEmail),
ServiceProvider, ServiceProvider,
"en"))) "en")))
.ShouldBe("Welcome {{model.name}} to the abp.io!"); .ShouldBe(WelcomeEmailEnglishContent);
(await _virtualFileTemplateContentContributor.GetOrNullAsync( (await VirtualFileTemplateContentContributor.GetOrNullAsync(
new TemplateContentContributorContext(_templateDefinitionManager.Get(TestTemplates.WelcomeEmail), new TemplateContentContributorContext(TemplateDefinitionManager.Get(TestTemplates.WelcomeEmail),
ServiceProvider, ServiceProvider,
"tr"))) "tr")))
.ShouldBe("Merhaba {{model.name}}, abp.io'ya hoşgeldiniz!"); .ShouldBe(WelcomeEmailTurkishContent);
} }
[Fact] [Fact]
public async Task Should_Get_Non_Localized_Template_Content() public async Task Should_Get_Non_Localized_Template_Content()
{ {
(await _virtualFileTemplateContentContributor.GetOrNullAsync( (await VirtualFileTemplateContentContributor.GetOrNullAsync(
new TemplateContentContributorContext( new TemplateContentContributorContext(
_templateDefinitionManager.Get(TestTemplates.ForgotPasswordEmail), TemplateDefinitionManager.Get(TestTemplates.ForgotPasswordEmail),
ServiceProvider, ServiceProvider,
null))) null)))
.ShouldBe("{{L \"HelloText\" model.name}}, {{L \"HowAreYou\" }}. Please click to the following link to get an email to reset your password!"); .ShouldBe(ForgotPasswordEmailEnglishContent);
} }
} }
} }

3
nupkg/common.ps1

@ -138,7 +138,10 @@ $projects = (
"framework/src/Volo.Abp.Sms.Aliyun", "framework/src/Volo.Abp.Sms.Aliyun",
"framework/src/Volo.Abp.Specifications", "framework/src/Volo.Abp.Specifications",
"framework/src/Volo.Abp.TestBase", "framework/src/Volo.Abp.TestBase",
"framework/src/Volo.Abp.TextTemplating.Abstractions",
"framework/src/Volo.Abp.TextTemplating", "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.Threading",
"framework/src/Volo.Abp.Timing", "framework/src/Volo.Abp.Timing",
"framework/src/Volo.Abp.UI", "framework/src/Volo.Abp.UI",

Loading…
Cancel
Save