├── .gitattributes
├── .gitignore
├── README.md
└── Source
├── Xipton.Razor.Example
├── App.config
├── Embedded
│ └── embeddedTemplate.cshtml
├── Models
│ ├── MyProductList.cs
│ └── Person.cs
├── Program.cs
├── Properties
│ └── AssemblyInfo.cs
├── Views
│ ├── Other
│ │ └── html.cshtml
│ ├── Reports
│ │ ├── Products.cshtml
│ │ ├── _ViewStart.cshtml
│ │ └── _productGrid.cshtml
│ ├── Shared
│ │ ├── _Layout1.cshtml
│ │ └── _Layout2.cshtml
│ └── _ViewStart.cshtml
├── Web.config
├── Xipton.Razor.Example.csproj
└── packages.config
├── Xipton.Razor.UnitTest
├── App.config
├── ConfigTest.cs
├── LiteralStringTest.cs
├── Properties
│ └── AssemblyInfo.cs
├── TemplateTest.cs
├── ViewBagTest.cs
├── VirtualPathBuilderTest.cs
├── Xipton.Razor.UnitTest.csproj
├── legacy
│ └── web.config
├── packages.config
└── unmanaged.dll
├── Xipton.Razor.sln
└── Xipton.Razor
├── Config
├── ConfigElement.cs
├── IRazorConfigInitializer.cs
├── RazorConfig.cs
├── RootOperatorElement.cs
├── TemplateConfigurationException.cs
├── TemplatesElement.cs
├── XElementExtension.cs
├── XmlConfigurationSection.cs
└── xipton.razor.config
├── Core
├── ContentManager.cs
├── ContentModifiedArgs.cs
├── ContentProvider
│ ├── CompositeContentProvider.cs
│ ├── EmbeddedResourceContentProvider.cs
│ ├── FileContentProvider.cs
│ └── MemoryContentProvider.cs
├── DynamicData.cs
├── Generator
│ ├── CSharp
│ │ ├── XiptonCSharpCodeLanguage.cs
│ │ └── XiptonCSharpCodeParser.cs
│ ├── IXiptonCodeLanguage.cs
│ ├── SetModelCodeGenerator.cs
│ ├── VB
│ │ ├── XiptonVBCodeLanguage.cs
│ │ └── XiptonVBCodeParser.cs
│ └── XiptonEngineHost.cs
├── HelperResult.cs
├── IContentProvider.cs
├── ITemplateController.cs
├── TemplateBindingException.cs
├── TemplateCompileException.cs
├── TemplateException.cs
├── TemplateFactory.cs
├── TemplateParseException.cs
├── TemplateTreeException.cs
└── VirtualPathBuilder.cs
├── Extension
├── AppDomainExtension.cs
├── AssemblyExtension.cs
├── ObjectExtension.cs
├── StringExtension.cs
├── TemplateExtension.cs
└── TypeExtension.cs
├── ILiteralString.cs
├── IRazorMachine.cs
├── ITemplate.cs
├── ITemplate`1.cs
├── LiteralString.cs
├── Properties
└── AssemblyInfo.cs
├── RazorContext.cs
├── RazorMachine.cs
├── TemplateBase.cs
├── TemplateBase`1.cs
├── Xipton.Razor.Overview.cd
├── Xipton.Razor.csproj
├── legacy
└── web.config
└── packages.config
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 | *.sln merge=union
7 | *.csproj merge=union
8 | *.vbproj merge=union
9 | *.fsproj merge=union
10 | *.dbproj merge=union
11 |
12 | # Standard to msysgit
13 | *.doc diff=astextplain
14 | *.DOC diff=astextplain
15 | *.docx diff=astextplain
16 | *.DOCX diff=astextplain
17 | *.dot diff=astextplain
18 | *.DOT diff=astextplain
19 | *.pdf diff=astextplain
20 | *.PDF diff=astextplain
21 | *.rtf diff=astextplain
22 | *.RTF diff=astextplain
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs)
2 | bin
3 | obj
4 |
5 | # Resharper folder
6 | _*
7 |
8 | # mstest test results
9 | TestResults
10 |
11 |
12 | # User files #
13 | ###################
14 | *.user
15 | *.suo
16 |
17 |
18 | # Logs and databases #
19 | ######################
20 | *.log
21 | *.sql
22 | *.sqlite
23 |
24 | # OS generated files #
25 | ######################
26 | .DS_Store
27 | .DS_Store?
28 | ._*
29 | .Spotlight-V100
30 | .Trashes
31 | Icon?
32 | ehthumbs.db
33 | Thumbs.db
34 |
35 | [Rr]elease*/
36 | _ReSharper*/
37 | [Tt]est[Rr]esult*
38 | packages/
39 | [Hh]elp/
40 | *.scc
41 |
42 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## RazorMachine ###
2 |
3 | var rm = new RazorMachine();
4 | var result =
5 | rm.Execute("Hello @Model.FirstName @Model.LastName", new {FirstName="John", LastName="Smith"});
6 | Console.WriteLine(result);
7 |
8 | RazorMachine is a robust and easy to use .Net Razor v2/v3 template engine. The master branch uses Razor v3. This implementation supports layouts (masterpages) and a _viewStart construct, just like MVC does support these features. The RazorEngine works independently from MVC. It only needs the System.Web.Razor reference. It almost works exacly like Asp.Net MVC. Take a look at https://github.com/jlamfers/RazorMachine/wiki/Examples to see how easily this framework works.
9 |
10 | This RazorEngine originally was published at CodeProject
11 |
12 | ## Install ##
13 |
14 | There is a package available at NuGet. To install RazorMachine using NuGet, run the following command in the Package Manager Console
15 | ```
16 | PM> Install-Package RazorMachine
17 | ```
18 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor.Example/App.config:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor.Example/Embedded/embeddedTemplate.cshtml:
--------------------------------------------------------------------------------
1 | @model Xipton.Razor.Example.Models.Person
2 | EMBEDDED RESOURCE TEMPLATE SAYS: Hello @Model.FirstName @Model.LastName
3 | @{
4 | }
5 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor.Example/Models/MyProductList.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Xipton.Razor.Example.Models {
4 | public class MyProduct
5 | {
6 | public string Name { get; set; }
7 | public double Price { get; set; }
8 | }
9 |
10 | public class MyProductList : List {
11 | public MyProductList()
12 | {
13 | Add("Toyota ", 20.245)
14 | .Add("Opel ", 12.938)
15 | .Add("BMW ", 24.837)
16 | .Add("Skoda ", 19.298);
17 | }
18 |
19 | private MyProductList Add(string name, double price){
20 | Add(new MyProduct{Name = name, Price = price});
21 | return this;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor.Example/Models/Person.cs:
--------------------------------------------------------------------------------
1 | namespace Xipton.Razor.Example.Models {
2 | public class Person {
3 | public string FirstName { get; set; }
4 | public string LastName { get; set; }
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor.Example/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Xipton.Razor.Example.Models;
4 |
5 | namespace Xipton.Razor.Example {
6 | class Program {
7 |
8 | // since the with the first examples we do not want to use any file content from the
9 | // ./Views folder so we remove all content providers and thus the file content provider as well
10 | private static RazorMachine _rm = CreateRazorMachineWithoutContentProviders();
11 |
12 | static void Main(string[] args) {
13 |
14 | // Examples from the CodeProject article
15 | VerifyExample(1);
16 | Example1();
17 | VerifyExample(2);
18 | Example2();
19 | VerifyExample(3);
20 | Example3();
21 | VerifyExample(4);
22 | Example4();
23 | VerifyExample(5);
24 | Example5();
25 | VerifyExample(6);
26 | Example6();
27 | VerifyExample(7);
28 | Example7();
29 | VerifyExample(8);
30 | Example8();
31 | VerifyExample(9);
32 | Example9();
33 | VerifyExample(10);
34 | Example10();
35 |
36 | VerifyExample("RunEmbeddedTemplate");
37 | RunEmbeddedTemplate();
38 |
39 | VerifyExample("RunProductListTemplateFromFile");
40 | RunProductListTemplateFromFile();
41 |
42 | VerifyExample("RunHtmlTemplate");
43 | RunHtmlTemplate();
44 |
45 |
46 | Console.Write("Completed all examples. Press any key to exit...");
47 | Console.ReadLine();
48 | }
49 |
50 | private static void VerifyExample(int exampleNr) {
51 | VerifyExample(exampleNr.ToString());
52 | }
53 | private static void VerifyExample(string name) {
54 | Console.WriteLine("\r\n***** Press [Enter] to run example {0} or [Esc] to exit.\r\n",name);
55 | if (Console.ReadKey().Key == ConsoleKey.Escape){
56 | Environment.Exit(0);
57 | }
58 |
59 | }
60 |
61 | private static RazorMachine CreateRazorMachineWithoutContentProviders(bool includeGeneratedSourceCode=false, string rootOperatorPath = null, bool htmlEncode = true) {
62 | var rm = new RazorMachine(includeGeneratedSourceCode: includeGeneratedSourceCode, htmlEncode: htmlEncode, rootOperatorPath: rootOperatorPath);
63 | rm.Context.TemplateFactory.ContentManager.ClearAllContentProviders();
64 | return rm;
65 | }
66 |
67 | // Example 1 - Executing a template
68 | public static void Example1() {
69 | ITemplate template = _rm.ExecuteContent("Razor says: Hello @Model.FirstName @Model.LastName", new { FirstName = "John", LastName = "Smith" });
70 | Console.WriteLine(template.Result);
71 | }
72 |
73 | // Example 2 - Executing a template using a layout
74 | public static void Example2() {
75 | _rm.RegisterTemplate("~/shared/_layout.cshtml", "BEGIN TEMPLATE \r\n @RenderBody() \r\nEND TEMPLATE");
76 | ITemplate template = _rm.ExecuteContent("@{Layout=\"_layout\";} Razor says: Hello @Model.FirstName @Model.LastName", new { FirstName = "John", LastName = "Smith" });
77 | Console.WriteLine(template); // template.ToString() evaluates to template.Result
78 | }
79 |
80 | //Example 3 - Executing a template using a layout and _viewStart
81 | public static void Example3() {
82 | _rm.RegisterTemplate("~/shared/_layout.cshtml", "BEGIN TEMPLATE \r\n @RenderBody() \r\nEND TEMPLATE");
83 | _rm.RegisterTemplate("~/_viewstart.cshtml", "@{Layout=\"_layout\";}");
84 | ITemplate template = _rm.ExecuteContent("Razor says: Hello @Model.FirstName @Model.LastName", new { FirstName = "John", LastName = "Smith" });
85 | Console.WriteLine(template); // same result as example 2
86 | }
87 |
88 | //Example 4 - Executing a template by a virtual path using a layout and _viewStart
89 | public static void Example4() {
90 |
91 | _rm.RegisterTemplate("~/shared/_layout.cshtml", "BEGIN TEMPLATE \r\n @RenderBody() \r\nEND TEMPLATE");
92 | _rm.RegisterTemplate("~/_viewstart.cshtml", "@{Layout=\"_layout\";}");
93 | _rm.RegisterTemplate("~/simpleTemplate.cshtml", "Razor says: Hello @Model.FirstName @Model.LastName");
94 |
95 | ITemplate template = _rm.ExecuteUrl("~/simpleTemplate.cshtml", new { FirstName = "John", LastName = "Smith" });
96 | Console.WriteLine(template); // same result as example 2
97 |
98 | }
99 |
100 | //Example 5 - Returning information from anywhere (even from a layout) to the caller using the ViewBag
101 | public static void Example5() {
102 | _rm.RegisterTemplate("~/shared/_layout.cshtml", "@{ViewBag.PiValue=3.1415927;}");
103 | _rm.RegisterTemplate("~/_viewstart.cshtml", "@{Layout=\"_layout\";}");
104 | ITemplate template = _rm.ExecuteContent("Anything");
105 | Console.WriteLine(template.ViewBag.PiValue); // => writes 3.1415927
106 | }
107 |
108 | //Example 6 - Adding information from anywhere to a predefined ViewBag and returning it to the caller
109 | public static void Example6() {
110 | _rm.RegisterTemplate("~/shared/_layout.cshtml", "@{ViewBag.Values.Add(3.1415927);}");
111 | _rm.RegisterTemplate("~/_viewstart.cshtml", "@{Layout=\"_layout\";}");
112 | ITemplate template = _rm.ExecuteContent("Anything", viewbag: new { Values = new List { 0, 1, 2 } });
113 | Console.WriteLine(template.ViewBag.Values[3]); // => writes 3.1415927
114 | }
115 |
116 | //Example 7 - Show generated code
117 | public static void Example7() {
118 | var rm = CreateRazorMachineWithoutContentProviders(includeGeneratedSourceCode: true);
119 | rm.RegisterTemplate("~/shared/_layout.cshtml", "BEGIN TEMPLATE \r\n @RenderBody() \r\nEND TEMPLATE");
120 | rm.RegisterTemplate("~/_viewstart.cshtml", "@{Layout=\"_layout\";}");
121 | ITemplate template = rm.ExecuteContent("Razor says: Hello @Model.FirstName @Model.LastName", new { FirstName = "John", LastName = "Smith" });
122 | Console.WriteLine(template); // writes output result
123 | Console.WriteLine(template.GeneratedSourceCode); // writes generated source for template
124 | Console.WriteLine(template.Childs[0].GeneratedSourceCode); // writes generated source for layout
125 | }
126 |
127 | //Example 8 - HTML encoding
128 | public static void Example8() {
129 | _rm.RegisterTemplate("~/shared/_layout.cshtml", "@RenderBody()"); // replace _layout by "RenderBody only" template to ensure output
130 |
131 | // not encoded since all output is literal content
132 | Console.WriteLine(_rm.ExecuteContent("Tom & Jerry").Result);
133 |
134 | // encoded since the content is written as a string value
135 | // and by default HtmlEncode is on for written content
136 | Console.WriteLine(_rm.ExecuteContent("@Model.Text", new { Text = "Tom & Jerry" }).Result);
137 |
138 | // not encoded since content is a written as a raw string
139 | Console.WriteLine(_rm.ExecuteContent("@Raw(Model.Text)", new { Text = "Tom & Jerry" }).Result);
140 |
141 | // not encoded since HtmlEncoding is turend off in code
142 | Console.WriteLine(_rm.ExecuteContent("@{HtmlEncode=false;} @Model.Text", new { Text = "Tom & Jerry" }).Result);
143 |
144 | var rm = CreateRazorMachineWithoutContentProviders(htmlEncode: false);
145 | rm.Context.TemplateFactory.ContentManager.ClearAllContentProviders();
146 | // not encoded since now html encoding if off by default, still you can set it on in code
147 | Console.WriteLine(rm.ExecuteContent("@Model.Text", new { Text = "Tom & Jerry" }).Result);
148 | }
149 |
150 | //Example 9 - Root operator is resolved directly
151 | public static void Example9() {
152 | var rm = CreateRazorMachineWithoutContentProviders(rootOperatorPath: "/MyAppName");
153 | rm.RegisterTemplate("~/MyTemplate", "Some Link");
154 | var template = rm.ExecuteUrl("/MyAppName/MyTemplate");
155 | // same result as:
156 | template = rm.ExecuteUrl("~/MyTemplate");
157 | Console.WriteLine(template); // writes: Some Link
158 |
159 | }
160 |
161 | //Example 10 - Razor 2: Attributes with null values are not rendered
162 | public static void Example10() {
163 | var template = _rm.ExecuteContent("Some Link", new { Brand = "Toyota", NullValue = (string)null });
164 | Console.WriteLine(template); // writes: Some Link
165 | }
166 |
167 |
168 | // ********************* Other examples ********************************************************************************* //
169 |
170 | public static void RunEmbeddedTemplate() {
171 | // this example only works if the embedded content provider has been configured. Here it is configured at app.config, includeGeneratedSourceCode is forced to true
172 | var rm = new RazorMachine(includeGeneratedSourceCode:true); // => default configuration from app.config is loaded
173 | var t = rm.ExecuteUrl("~/embeddedTemplate");
174 | Console.WriteLine("Generated source code:");
175 | Console.WriteLine(t.GeneratedSourceCode);
176 | Console.WriteLine("Generated output:");
177 | Console.WriteLine(t); // => writes the embedded template's result
178 | //NOTE: since now all content providers (file content providers as well) are loaded the ~/ViewStart.cshtml from the ./Views folder is executed as well
179 | }
180 |
181 | ///
182 | /// This example creates a product list using a simple product grid productGrid (at ./Views/Reports/).
183 | /// The grid implicitly "knows" the product model because the grid is a child of Products, which is executed together with the MyProductList().
184 | /// The layout is _layout2 which is set in memory at "~/_ViewStart", thus override the file ./Views/_ViewStart.cshtml
185 | ///
186 | public static void RunProductListTemplateFromFile() {
187 | var rm = new RazorMachine(includeGeneratedSourceCode: true); // => default configuration from app.config is loaded, includeGeneratedSourceCode is forced to true
188 | rm.RegisterTemplate("~/_ViewStart", "@{Layout=\"_Layout2\";}"); // => change (override) layout in memory to _layout2
189 |
190 | var t = rm.ExecuteUrl("~/Reports/Products", new MyProductList());
191 |
192 | Console.WriteLine("Generated template source code:");
193 | Console.WriteLine(t.GeneratedSourceCode);
194 |
195 | Console.WriteLine("Generated layout source code:");
196 | Console.WriteLine(t.Childs[t.Childs.Count - 1].GeneratedSourceCode); // layout always is the last child bacause it is rendered at last
197 |
198 | Console.WriteLine("Generated grid source code:");
199 | Console.WriteLine(t.Childs[0].GeneratedSourceCode);
200 |
201 | Console.WriteLine("Generated output:");
202 | Console.WriteLine(t); // => writes the embedded template's result
203 | }
204 |
205 | public static void RunHtmlTemplate(){
206 | Console.WriteLine(new RazorMachine(includeGeneratedSourceCode: true).ExecuteUrl("/Other/Html",new{FirstName="Dick",LastName="Tracy"}));
207 | }
208 |
209 |
210 |
211 | }
212 | }
213 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor.Example/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Xipton.Razor.Example")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Xipton")]
12 | [assembly: AssemblyProduct("Xipton.Razor.Example")]
13 | [assembly: AssemblyCopyright("Copyright © 2013")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("ad0f2ba7-e72e-4a4c-b2dd-84557e785d80")]
24 |
25 | [assembly: AssemblyVersion("3.1.0.0")]
26 | [assembly: AssemblyFileVersion("3.1.0.0")]
27 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor.Example/Views/Other/html.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 | @{this.HtmlEncode = true; // default value can be configured}
4 |
5 | }
6 | @*Razor 2 feature: root operator is resolved directly *@
7 |
8 |
9 | @*Razor 2 related feature: conditional attributes: attributes are not rendered if the correponding value is null or empty*@
10 | @{
11 | string nullValue = null;
12 | }
13 |
14 |
15 | Hello @Model.FirstName @Model.LastName
16 |
17 | Hello Tom & Jerry
18 | @("Hello Tom & Jerry")
19 | @Raw("Hello Tom & Jerry")
20 |
21 | The following C# code was generated for this template:
22 | @Raw(GeneratedSourceCode)
23 |
24 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor.Example/Views/Reports/Products.cshtml:
--------------------------------------------------------------------------------
1 | @* intellisense works *@
2 | Overview of products at @DateTime.Now
3 | @RenderPage("_productGrid",skipLayout:true) @* layout is skipped (as an example; it is disabled at _productGrid as well. *@
4 |
5 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor.Example/Views/Reports/_ViewStart.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | var br = Environment.NewLine;
3 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor.Example/Views/Reports/_productGrid.cshtml:
--------------------------------------------------------------------------------
1 | @using Xipton.Razor.Example.Models
2 | @model MyProductList
3 |
4 | @{Layout = null; // enforce to disable any layout setting
5 | }
6 |
7 | @* intellisense should work at this template *@
8 |
9 | Product list:
10 | Name Price
11 | ---------------
12 | @foreach(var m in Model){
13 | @m.Name @m.Price@br
14 | }
15 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor.Example/Views/Shared/_Layout1.cshtml:
--------------------------------------------------------------------------------
1 | BEGIN LAYOUT @VirtualPath
2 | (at @RazorContext.TemplateFactory.ContentManager.TryGetResourceName(VirtualPath))
3 | @RenderBody()
4 | END
--------------------------------------------------------------------------------
/Source/Xipton.Razor.Example/Views/Shared/_Layout2.cshtml:
--------------------------------------------------------------------------------
1 | BEGIN _Layout2
2 | @RenderBody()
3 | END _Layout2
--------------------------------------------------------------------------------
/Source/Xipton.Razor.Example/Views/_ViewStart.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | // content of ViewStart.cshtml at file system
3 | Layout = "_layout1"; @* layout1 is at the shared folder *@
4 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor.Example/Web.config:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor.Example/Xipton.Razor.Example.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | x86
6 | 8.0.30703
7 | 2.0
8 | {B6E046A6-4EBC-48EC-A454-8399AB3DD9AF}
9 | Exe
10 | Properties
11 | Xipton.Razor.Example
12 | Xipton.Razor.Example
13 | v4.5
14 |
15 |
16 | 512
17 |
18 |
19 | AnyCPU
20 | true
21 | full
22 | false
23 | bin\Debug\
24 | DEBUG;TRACE
25 | prompt
26 | 4
27 | false
28 |
29 |
30 | x86
31 | pdbonly
32 | true
33 | bin\Release\
34 | TRACE
35 | prompt
36 | 4
37 | false
38 |
39 |
40 |
41 |
42 |
43 | False
44 | ..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | Code
54 |
55 |
56 |
57 |
58 | Designer
59 |
60 |
61 |
62 |
63 | PreserveNewest
64 |
65 |
66 | PreserveNewest
67 |
68 |
69 | PreserveNewest
70 |
71 |
72 | PreserveNewest
73 |
74 |
75 | Always
76 |
77 |
78 | PreserveNewest
79 |
80 |
81 | PreserveNewest
82 |
83 |
84 |
85 |
86 | Designer
87 |
88 |
89 |
90 |
91 | {3a7a2f2f-0b57-47f9-8e1a-d34ecb961831}
92 | Xipton.Razor
93 |
94 |
95 |
96 |
103 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor.Example/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor.UnitTest/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor.UnitTest/ConfigTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using Microsoft.VisualStudio.TestTools.UnitTesting;
6 | using Xipton.Razor.Config;
7 |
8 | namespace Xipton.Razor.UnitTest {
9 | [TestClass]
10 | public class ConfigTest {
11 |
12 | [TestMethod]
13 | public void ConfigCanBeCreated(){
14 | var config = new RazorConfig();
15 | Assert.IsNotNull(config.ContentProviders);
16 | Assert.IsNotNull(config.Namespaces);
17 | Assert.IsNotNull(config.References);
18 | Assert.IsNotNull(config.RootOperator);
19 | Assert.IsNotNull(config.Templates);
20 | Assert.IsTrue(config.References.Any(r => r.Contains("*")));
21 | }
22 | [TestMethod]
23 | public void ConfigCanBeCreatedWithoutWildcards()
24 | {
25 | var config = new RazorConfig(false);
26 | Assert.IsNotNull(config.ContentProviders);
27 | Assert.IsNotNull(config.Namespaces);
28 | Assert.IsNotNull(config.References);
29 | Assert.IsNotNull(config.RootOperator);
30 | Assert.IsNotNull(config.Templates);
31 | Assert.IsFalse(config.References.Any(r => r.Contains("*")));
32 | }
33 |
34 | [TestMethod]
35 | public void ConfigIsLoadedFromConfig() {
36 | var config = new RazorConfig();
37 | Assert.IsFalse(config.Templates.IncludeGeneratedSourceCode);
38 | config.Initializer.TryInitializeFromConfig();
39 | Assert.IsTrue(config.Templates.IncludeGeneratedSourceCode);
40 | }
41 |
42 | [TestMethod]
43 | public void ConfigIsLoadedFromFile() {
44 | var config = new RazorConfig();
45 | Assert.IsFalse(config.Templates.IncludeGeneratedSourceCode);
46 | config.Initializer.InitializeByXmlFileName("Xipton.Razor.UnitTest.dll.config");
47 | Assert.IsTrue(config.Templates.IncludeGeneratedSourceCode);
48 | }
49 |
50 | [TestMethod]
51 | public void ConfigIsLoadedFromValues() {
52 | var config = new RazorConfig();
53 | config.Initializer.InitializeByValues(defaultExtension: ".vb");
54 | Assert.AreEqual(config.Templates.DefaultExtension,".vb");
55 | }
56 |
57 | [TestMethod]
58 | public void ConfigIsLoadedFromXml() {
59 | var config = new RazorConfig();
60 | config.Initializer.InitializeByXmlContent(
61 | @"
62 |
63 |
64 |
65 | "
66 | );
67 | Assert.AreEqual(config.RootOperator.Path, "/foo");
68 | }
69 |
70 | [TestMethod]
71 | [ExpectedException(typeof(InvalidOperationException))]
72 | public void ConfigCannotBeModifiedAfterRazorMachineInitialization(){
73 |
74 | var rm = new RazorMachine();
75 | rm.Context.Config.Initializer.InitializeByValues(rootOperatorPath: "/foo");
76 |
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor.UnitTest/LiteralStringTest.cs:
--------------------------------------------------------------------------------
1 | // ReSharper disable HeuristicUnreachableCode
2 | using System;
3 | using Microsoft.VisualStudio.TestTools.UnitTesting;
4 |
5 | namespace Xipton.Razor.UnitTest {
6 | [TestClass]
7 | public class LiteralStringTest {
8 |
9 | [TestMethod]
10 | public void LiteralStringCanBeInstantiated() {
11 | new LiteralString(null);
12 | new LiteralString(string.Empty);
13 | new LiteralString("foo");
14 | }
15 |
16 | [TestMethod]
17 | public void LiteralStringCanBeComparedToSystemString() {
18 | Assert.IsTrue(new LiteralString(null).Equals(null));
19 | new LiteralString(string.Empty).Equals(string.Empty);
20 | new LiteralString("foo").Equals("foo");
21 |
22 | Assert.IsTrue(new LiteralString(string.Empty) == string.Empty);
23 | Assert.IsTrue(new LiteralString("foo") == "foo");
24 |
25 | Assert.IsFalse(new LiteralString(null) != null); // !
26 | Assert.IsFalse(new LiteralString(string.Empty) != string.Empty);
27 | Assert.IsFalse(new LiteralString("foo") != "foo");
28 | }
29 |
30 | [TestMethod]
31 | public void LiteralStringCanBeAssignedFromSystemString() {
32 | LiteralString literalString = "foo";
33 | Assert.AreEqual(literalString,"foo");
34 | Assert.IsTrue(literalString == "foo");
35 |
36 | string nullString = null;
37 | literalString = nullString;
38 | Assert.IsTrue(literalString.Equals(nullString)); //! => literalString object itself is not null
39 | Assert.IsTrue(literalString == nullString);
40 | Assert.IsTrue(literalString == null);//! => literalString object itself is not null
41 | }
42 |
43 | [TestMethod]
44 | public void StringCanBeAssignedFromLiteralString() {
45 | LiteralString literalString = "foo";
46 | string s = literalString;
47 | Assert.AreEqual(literalString, s);
48 | Assert.IsTrue(s == "foo");
49 |
50 | literalString = (string) null;
51 | s = literalString;
52 | Assert.IsTrue(literalString == s);
53 | Assert.IsTrue(s == null);
54 | }
55 |
56 | [TestMethod]
57 | public void NullStringBehaviorCheck(){
58 | Assert.IsTrue(new LiteralString(null) == null); // !!
59 | Assert.IsTrue(new LiteralString(null).ToString() == string.Empty); // !! => ToString() never returns null;
60 |
61 | LiteralString s = (string)null;
62 | Assert.IsTrue(s == null);
63 | Assert.IsTrue(s.ToString().Length == 0); //!!
64 |
65 | s = null; // instead of (string)null => no implicit cast operator
66 | Assert.IsTrue(s == null);
67 | Exception caught = null;
68 | try{
69 | Assert.IsTrue(s.ToString().Length == 0);
70 | }
71 | catch (NullReferenceException ex) {
72 | caught = ex;
73 | Console.WriteLine(ex.Message);
74 | }
75 | Assert.IsNotNull(caught);
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor.UnitTest/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Xipton.Razor.UnitTest")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Xipton")]
12 | [assembly: AssemblyProduct("Xipton.Razor.UnitTest")]
13 | [assembly: AssemblyCopyright("Copyright © 2013")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("f45d36c8-d0f8-4be6-a7ef-d3bda2692b74")]
24 |
25 | [assembly: AssemblyVersion("3.1.0.0")]
26 | [assembly: AssemblyFileVersion("3.1.0.0")]
27 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor.UnitTest/ViewBagTest.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Diagnostics;
3 | using Microsoft.VisualStudio.TestTools.UnitTesting;
4 | using Xipton.Razor.Core;
5 | using Xipton.Razor.Extension;
6 |
7 | namespace Xipton.Razor.UnitTest
8 | {
9 | [TestClass]
10 | public class ViewBagTest
11 | {
12 |
13 | private static RazorMachine NewEngine(string virtualRoot = null) {
14 | var setup = @"
15 |
16 |
17 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | ".FormatWith(virtualRoot ?? "/");
27 |
28 | return new RazorMachine(setup);
29 | }
30 |
31 | [TestMethod]
32 | public void ViewBagValueIsSet()
33 | {
34 | var engine = new RazorMachine()
35 | .RegisterTemplate("~/Test", "@{ViewBag.Foo = 1;} Hello World!");
36 | var template = engine.ExecuteUrl("~/Test");
37 | Debug.WriteLine(template.Result); // => prints: Hello World!
38 | Assert.AreEqual(1, template.ViewBag.Foo);
39 | }
40 |
41 | [TestMethod]
42 | public void EmptyViewBagCanBeAssignedTo()
43 | {
44 | var engine = NewEngine("/foo");
45 | engine.RegisterTemplate("~/Test.cshtml", "@{ViewBag.Foo = 1;}");
46 | var template = engine.ExecuteUrl("/foo/Test");
47 | Assert.AreEqual(1,template.ViewBag.Foo);
48 | }
49 |
50 | [TestMethod]
51 | [ExpectedException(typeof(TemplateBindingException))]
52 | public void EmptyViewBagThrowsRuntimeBinderExceptionOnInvalidReference()
53 | {
54 | var engine = NewEngine();
55 | engine.RegisterTemplate("/Test", "@{int i = (int)ViewBag.Foo;}");
56 | engine.ExecuteUrl("/Test");
57 | }
58 |
59 | [TestMethod]
60 | public void ViewBagCanBe_AnonymousInstance()
61 | {
62 | var engine = NewEngine();
63 | engine.RegisterTemplate("~/Test/Foo", "@{var i = (int)ViewBag.Foo;Assert.AreEqual(10,i);}");
64 | engine.ExecuteUrl("/Test/Foo",viewbag:new{Foo = 10});
65 | }
66 | [TestMethod]
67 | public void ViewBagCanBe_KeyValueDictionary()
68 | {
69 | var engine = NewEngine();
70 | engine.RegisterTemplate("~/Test.cshtml", "@{var i = (int)ViewBag.Foo;Assert.AreEqual(10,i);}");
71 | engine.ExecuteUrl("~/Test", viewbag: new Dictionary{{"Foo",10}});
72 |
73 | }
74 | class FooHolder
75 | {
76 | // ReSharper disable UnusedMember.Local
77 | public int Foo { get { return 10; } }
78 | // ReSharper restore UnusedMember.Local
79 | }
80 | [TestMethod]
81 | public void ViewBagCanBe_Class()
82 | {
83 | var engine = NewEngine();
84 | engine.RegisterTemplate("~/Test.cshtml", "@{var i = (int)ViewBag.Foo;Assert.AreEqual(10,i);}");
85 | engine.ExecuteUrl("~/Test", viewbag: new FooHolder());
86 |
87 | }
88 | [TestMethod]
89 | public void ViewBagFromParentIsReferencedImplicitly()
90 | {
91 | var engine = NewEngine();
92 | engine.RegisterTemplate("~/Parent.cshtml", "@{ViewBag.Title=10;} @RenderPage(\"Child\")");
93 | engine.RegisterTemplate("~/Child.cshtml", "@{var i = (int)ViewBag.Title;Assert.AreEqual(10,i);}");
94 | engine.ExecuteUrl("~/Parent");
95 |
96 | }
97 |
98 | [TestMethod]
99 | public void ViewBagAtChildInstantiatesRootViewBagIfChildHasNoViewBag()
100 | {
101 | var engine = NewEngine();
102 | engine.RegisterTemplate("~/Parent.cshtml", "@RenderPage(\"Child\") @{var i = (int)ViewBag.Title;Assert.AreEqual(10,i);}");
103 | engine.RegisterTemplate("~/Child.cshtml", "@RenderPage(\"Child2\")");
104 | engine.RegisterTemplate("~/Child2.cshtml", "@{ViewBag.Title=10;}");
105 | var template = engine.ExecuteUrl("~/Parent");
106 | Assert.AreEqual("~/Child2.cshtml", template.Childs[0].Childs[0].VirtualPath);
107 |
108 | }
109 |
110 |
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor.UnitTest/Xipton.Razor.UnitTest.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 8.0.30703
7 | 2.0
8 | {C7DA7CA0-86F9-4CA1-89EA-D1A23A4C7A2A}
9 | Library
10 | Properties
11 | Xipton.Razor.UnitTest
12 | Xipton.Razor.UnitTest
13 | v4.5
14 | 512
15 |
16 |
17 |
18 |
19 | true
20 | full
21 | false
22 | bin\Debug\
23 | DEBUG;TRACE
24 | prompt
25 | 4
26 | false
27 |
28 |
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 | false
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | False
44 | ..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | Always
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | Designer
64 |
65 |
66 |
67 | Always
68 |
69 |
70 |
71 |
72 | {3A7A2F2F-0B57-47F9-8E1A-D34ECB961831}
73 | Xipton.Razor
74 |
75 |
76 |
77 |
78 |
79 |
80 |
87 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor.UnitTest/legacy/web.config:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor.UnitTest/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor.UnitTest/unmanaged.dll:
--------------------------------------------------------------------------------
1 | this represents an unmanaged dll, for testing the handling of unmanged dlls
2 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2013
4 | VisualStudioVersion = 12.0.31101.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xipton.Razor.UnitTest", "Xipton.Razor.UnitTest\Xipton.Razor.UnitTest.csproj", "{C7DA7CA0-86F9-4CA1-89EA-D1A23A4C7A2A}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xipton.Razor.Example", "Xipton.Razor.Example\Xipton.Razor.Example.csproj", "{B6E046A6-4EBC-48EC-A454-8399AB3DD9AF}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xipton.Razor", "Xipton.Razor\Xipton.Razor.csproj", "{3A7A2F2F-0B57-47F9-8E1A-D34ECB961831}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|Any CPU = Debug|Any CPU
15 | Debug|Mixed Platforms = Debug|Mixed Platforms
16 | Debug|x86 = Debug|x86
17 | Release|Any CPU = Release|Any CPU
18 | Release|Mixed Platforms = Release|Mixed Platforms
19 | Release|x86 = Release|x86
20 | EndGlobalSection
21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
22 | {C7DA7CA0-86F9-4CA1-89EA-D1A23A4C7A2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {C7DA7CA0-86F9-4CA1-89EA-D1A23A4C7A2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {C7DA7CA0-86F9-4CA1-89EA-D1A23A4C7A2A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
25 | {C7DA7CA0-86F9-4CA1-89EA-D1A23A4C7A2A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
26 | {C7DA7CA0-86F9-4CA1-89EA-D1A23A4C7A2A}.Debug|x86.ActiveCfg = Debug|Any CPU
27 | {C7DA7CA0-86F9-4CA1-89EA-D1A23A4C7A2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
28 | {C7DA7CA0-86F9-4CA1-89EA-D1A23A4C7A2A}.Release|Any CPU.Build.0 = Release|Any CPU
29 | {C7DA7CA0-86F9-4CA1-89EA-D1A23A4C7A2A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
30 | {C7DA7CA0-86F9-4CA1-89EA-D1A23A4C7A2A}.Release|Mixed Platforms.Build.0 = Release|Any CPU
31 | {C7DA7CA0-86F9-4CA1-89EA-D1A23A4C7A2A}.Release|x86.ActiveCfg = Release|Any CPU
32 | {B6E046A6-4EBC-48EC-A454-8399AB3DD9AF}.Debug|Any CPU.ActiveCfg = Debug|x86
33 | {B6E046A6-4EBC-48EC-A454-8399AB3DD9AF}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
34 | {B6E046A6-4EBC-48EC-A454-8399AB3DD9AF}.Debug|Mixed Platforms.Build.0 = Debug|x86
35 | {B6E046A6-4EBC-48EC-A454-8399AB3DD9AF}.Debug|x86.ActiveCfg = Debug|x86
36 | {B6E046A6-4EBC-48EC-A454-8399AB3DD9AF}.Debug|x86.Build.0 = Debug|x86
37 | {B6E046A6-4EBC-48EC-A454-8399AB3DD9AF}.Release|Any CPU.ActiveCfg = Release|x86
38 | {B6E046A6-4EBC-48EC-A454-8399AB3DD9AF}.Release|Mixed Platforms.ActiveCfg = Release|x86
39 | {B6E046A6-4EBC-48EC-A454-8399AB3DD9AF}.Release|Mixed Platforms.Build.0 = Release|x86
40 | {B6E046A6-4EBC-48EC-A454-8399AB3DD9AF}.Release|x86.ActiveCfg = Release|x86
41 | {B6E046A6-4EBC-48EC-A454-8399AB3DD9AF}.Release|x86.Build.0 = Release|x86
42 | {3A7A2F2F-0B57-47F9-8E1A-D34ECB961831}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
43 | {3A7A2F2F-0B57-47F9-8E1A-D34ECB961831}.Debug|Any CPU.Build.0 = Debug|Any CPU
44 | {3A7A2F2F-0B57-47F9-8E1A-D34ECB961831}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
45 | {3A7A2F2F-0B57-47F9-8E1A-D34ECB961831}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
46 | {3A7A2F2F-0B57-47F9-8E1A-D34ECB961831}.Debug|x86.ActiveCfg = Debug|Any CPU
47 | {3A7A2F2F-0B57-47F9-8E1A-D34ECB961831}.Release|Any CPU.ActiveCfg = Release|Any CPU
48 | {3A7A2F2F-0B57-47F9-8E1A-D34ECB961831}.Release|Any CPU.Build.0 = Release|Any CPU
49 | {3A7A2F2F-0B57-47F9-8E1A-D34ECB961831}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
50 | {3A7A2F2F-0B57-47F9-8E1A-D34ECB961831}.Release|Mixed Platforms.Build.0 = Release|Any CPU
51 | {3A7A2F2F-0B57-47F9-8E1A-D34ECB961831}.Release|x86.ActiveCfg = Release|Any CPU
52 | EndGlobalSection
53 | GlobalSection(SolutionProperties) = preSolution
54 | HideSolutionNode = FALSE
55 | EndGlobalSection
56 | EndGlobal
57 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Config/ConfigElement.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System.Xml.Linq;
9 |
10 | namespace Xipton.Razor.Config
11 | {
12 | public abstract class ConfigElement {
13 |
14 | public static TElement Create()
15 | where TElement : ConfigElement, new() {
16 | var e = new TElement();
17 | e.SetDefaults();
18 | return e;
19 | }
20 |
21 | internal ConfigElement TryLoadElement(XElement e) {
22 | if (e != null)
23 | Load(e);
24 | return this;
25 | }
26 |
27 | protected abstract void Load(XElement e);
28 | protected internal abstract void SetDefaults();
29 |
30 | }
31 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Config/IRazorConfigInitializer.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Web.Razor;
11 | using Xipton.Razor.Core;
12 |
13 | namespace Xipton.Razor.Config
14 | {
15 | public interface IRazorConfigInitializer
16 | {
17 | IRazorConfigInitializer InitializeByValues(
18 | Type baseType = null,
19 | string rootOperatorPath = null,
20 | RazorCodeLanguage language = null,
21 | string defaultExtension = null,
22 | string autoIncludeNameWithoutExtension = null,
23 | string sharedLocation = null,
24 | bool? includeGeneratedSourceCode = null,
25 | bool? htmlEncode = null,
26 | IEnumerable references = null,
27 | IEnumerable namespaces = null,
28 | IEnumerable> contentProviders = null,
29 | bool replaceReferences = false,
30 | bool replaceNamespaces = false,
31 | bool replaceContentProviders = false
32 | );
33 |
34 | IRazorConfigInitializer InitializeByXmlContent(string xmlContent);
35 |
36 | IRazorConfigInitializer InitializeByXmlFileName(string fileName);
37 | IRazorConfigInitializer TryInitializeFromConfig();
38 | RazorConfig AsReadOnly();
39 | }
40 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Config/RazorConfig.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Configuration;
11 | using System.IO;
12 | using System.Linq;
13 | using System.Reflection;
14 | using System.Web.Razor;
15 | using System.Xml;
16 | using System.Xml.Linq;
17 | using Xipton.Razor.Core;
18 | using Xipton.Razor.Core.ContentProvider;
19 | using Xipton.Razor.Extension;
20 |
21 | namespace Xipton.Razor.Config {
22 | ///
23 | /// Holds all configuration settings. The configuration is initialized together with the RazorMachine class.
24 | ///
25 | /// If the configuration is initialized by default (with no parameters) it is checked if a configuration section exists at
26 | /// the default application's configuration named xipton.razor.config. If such a section exists then that configuration is used. Else the configuration
27 | /// is initialized as default, i.e., using the C# compiler and using MVC complient settings.
28 | ///
29 | /// If you pass explicit settings with the constructor then at first the configuration is initialized as by default, as with the default constructor.
30 | /// After that all passed non null arguments override their correponding existing settings. For namespaces and references hold that by default
31 | /// these are merged with the already present configured (or default) namespaces and references, unless you specify that these arguments must replace
32 | /// the corresponding present settings.
33 | ///
34 | public sealed class RazorConfig : IRazorConfigInitializer
35 | {
36 | private readonly bool
37 | _allowWildcardReferences;
38 |
39 | private const string
40 | _rootElementName = "xipton.razor";
41 |
42 | private bool
43 | _isReadOnly;
44 |
45 | public RazorConfig(bool allowWildcardReferences = true)
46 | {
47 | _allowWildcardReferences = allowWildcardReferences;
48 | LoadDefaults();
49 | }
50 |
51 | #region Configuration Properties
52 | public RootOperatorElement RootOperator { get; private set; }
53 | public TemplatesElement Templates { get; private set; }
54 | public IList Namespaces { get; private set; }
55 | public IList References { get; private set; }
56 | public IList> ContentProviders { get; private set; }
57 | public IRazorConfigInitializer Initializer{
58 | get{
59 | EnsureNotReadonly();
60 | return this;
61 | }
62 | }
63 | #endregion
64 |
65 | #region IRazorConfigInitializer
66 |
67 | IRazorConfigInitializer IRazorConfigInitializer.InitializeByValues(
68 | Type baseType,
69 | string rootOperatorPath,
70 | RazorCodeLanguage language,
71 | string defaultExtension,
72 | string autoIncludeNameWithoutExtension,
73 | string sharedLocation,
74 | bool? includeGeneratedSourceCode,
75 | bool? htmlEncode,
76 | IEnumerable references,
77 | IEnumerable namespaces,
78 | IEnumerable> contentProviders,
79 | bool replaceReferences,
80 | bool replaceNamespaces,
81 | bool replaceContentProviders
82 | )
83 | {
84 |
85 | EnsureNotReadonly();
86 |
87 | RootOperator.Path = rootOperatorPath ?? RootOperator.Path;
88 |
89 | Templates.BaseType = baseType ?? Templates.BaseType;
90 | Templates.Language = language ?? Templates.Language;
91 | Templates.DefaultExtension = (defaultExtension ?? Templates.DefaultExtension).EmptyAsNull();
92 | Templates.AutoIncludeName = (autoIncludeNameWithoutExtension ?? Templates.AutoIncludeName).EmptyAsNull();
93 | Templates.SharedLocation = (sharedLocation ?? Templates.SharedLocation).EmptyAsNull();
94 | if (includeGeneratedSourceCode != null)
95 | Templates.IncludeGeneratedSourceCode = includeGeneratedSourceCode.Value;
96 | if (htmlEncode != null)
97 | Templates.HtmlEncode = htmlEncode.Value;
98 | if (references != null) {
99 | References = replaceReferences ? references.ToList().AsReadOnly() : References.Union(references, StringComparer.InvariantCultureIgnoreCase).ToList().AsReadOnly();
100 | }
101 | if (namespaces != null) {
102 | Namespaces = replaceNamespaces ? namespaces.ToList().AsReadOnly() : Namespaces.Union(namespaces).ToList().AsReadOnly();
103 | }
104 | if (contentProviders != null) {
105 | ContentProviders = replaceContentProviders ? contentProviders.ToList().AsReadOnly() : ContentProviders.Union(contentProviders).ToList().AsReadOnly();
106 | }
107 | return this;
108 | }
109 |
110 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "StringReader is disposed on XmlTextReader.Dispose()")]
111 | IRazorConfigInitializer IRazorConfigInitializer.InitializeByXmlContent(string xmlContent) {
112 | if (xmlContent == null) throw new ArgumentNullException("xmlContent");
113 | EnsureNotReadonly();
114 | using (var reader = new XmlTextReader(new StringReader(xmlContent))){
115 | LoadSettingsFromXDocumentOrElseDefaults(XDocument.Load(reader));
116 | }
117 | return this;
118 | }
119 |
120 | IRazorConfigInitializer IRazorConfigInitializer.InitializeByXmlFileName(string fileName) {
121 | if (fileName == null) throw new ArgumentNullException("fileName");
122 | EnsureNotReadonly();
123 | if (!File.Exists(fileName)){
124 | throw new FileNotFoundException("Configuration file '{0}' not found.".FormatWith(fileName), fileName);
125 | }
126 | using (var reader = new XmlTextReader(fileName))
127 | LoadSettingsFromXDocumentOrElseDefaults(XDocument.Load(reader));
128 | return this;
129 | }
130 |
131 | IRazorConfigInitializer IRazorConfigInitializer.TryInitializeFromConfig() {
132 | EnsureNotReadonly();
133 | var section = ConfigurationManager.GetSection("xipton.razor.config");
134 | XElement innerXml;
135 | if (section != null && (innerXml = section.CastTo().InnerXml) != null)
136 | LoadSettingsFromXDocumentOrElseDefaults(new XDocument(innerXml));
137 | return this;
138 | }
139 |
140 | RazorConfig IRazorConfigInitializer.AsReadOnly(){
141 | return AsReadonly();
142 | }
143 |
144 | #endregion
145 |
146 | #region Internal
147 | internal RazorConfig AsReadonly() {
148 | if (!_isReadOnly) {
149 | _isReadOnly = true;
150 | TryResolveWildcardReferences();
151 | }
152 | return this;
153 | }
154 | #endregion
155 |
156 | #region Private
157 | private void EnsureNotReadonly() {
158 | if (_isReadOnly)
159 | throw new InvalidOperationException("Configuration is read-only, after it has been registered inside the razor context, and cannot be modified anymore.");
160 | }
161 |
162 | private static IList CreateDefaultNamespaces() {
163 | return
164 | new List
165 | {
166 | "System",
167 | "System.Collections",
168 | "System.Collections.Generic",
169 | "System.Dynamic",
170 | "System.IO",
171 | "System.Linq",
172 | "Xipton.Razor.Extension"
173 | }.AsReadOnly();
174 | }
175 | private IList CreateDefaultReferences() {
176 | var references =
177 | new List
178 | {
179 | "mscorlib.dll",
180 | "system.dll",
181 | "system.core.dll",
182 | "microsoft.csharp.dll"
183 |
184 | };
185 | if (_allowWildcardReferences)
186 | {
187 | references.AddRange(new[]
188 | {
189 | "*.dll",
190 | "*.exe"
191 | });
192 | }
193 | return references.AsReadOnly();
194 | }
195 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "created instances are disposed on CompositeContentProvider.Dispose()")]
196 | private static IList> CreateDefaultContentProviders() {
197 | return new List> { () => new FileContentProvider(Directory.Exists("./Views".MakeAbsoluteDirectoryPath()) ? "./Views" : ".") }.AsReadOnly();
198 | }
199 |
200 | private void LoadSettingsFromXDocumentOrElseDefaults(XContainer config) {
201 | try {
202 |
203 | var rootDescendents = config.Descendants(_rootElementName);
204 |
205 | var xElements = rootDescendents as XElement[] ?? rootDescendents.ToArray();
206 | RootOperator = ConfigElement
207 | .Create()
208 | .TryLoadElement(xElements
209 | .Descendants("rootOperator")
210 | .SingleOrDefault()
211 | )
212 | .CastTo();
213 |
214 | Templates = ConfigElement
215 | .Create()
216 | .TryLoadElement(xElements
217 | .Descendants("templates")
218 | .SingleOrDefault()
219 | )
220 | .CastTo();
221 |
222 | Namespaces = xElements.HasClearChildElement("namespaces") ? new List() : CreateDefaultNamespaces();
223 | References = xElements.HasClearChildElement("references") ? new List() : CreateDefaultReferences();
224 | ContentProviders = xElements.HasClearChildElement("contentProviders") ? new List>() : CreateDefaultContentProviders();
225 |
226 | Namespaces = xElements
227 | .Descendants("namespaces")
228 | .SingleOrDefault(new XElement("namespaces"))
229 | .Descendants("add")
230 | .Select(xe => xe.GetAttributeValue("namespace"))
231 | .Union(Namespaces)
232 | .ToList()
233 | .AsReadOnly();
234 |
235 | References = xElements
236 | .Descendants("references")
237 | .SingleOrDefault(new XElement("references"))
238 | .Descendants("add")
239 | .Select(xe => xe.GetAttributeValue("reference"))
240 | .Union(References, StringComparer.InvariantCultureIgnoreCase)
241 | .ToList()
242 | .AsReadOnly();
243 |
244 | var contentProviderElements =
245 | xElements
246 | .Descendants("contentProviders")
247 | .SingleOrDefault(new XElement("contentProviders"))
248 | .Descendants("add");
249 |
250 | ContentProviders = ContentProviders.ToList();
251 | foreach (var e in contentProviderElements) {
252 | var el = e;
253 | ContentProviders.Add(
254 | () => Activator.CreateInstance(Type.GetType(el.GetAttributeValue("type"), true), true)
255 | .CastTo()
256 | .InitFromConfig(el)
257 | );
258 | }
259 | ContentProviders = ContentProviders.CastTo>>().AsReadOnly();
260 | }
261 | catch(TypeLoadException ex){
262 | throw new TemplateConfigurationException("Unable to load type named '{0}' at your xipton.razor configuration. Please correct the corresponding configuration setting.".FormatWith(ex.TypeName),ex);
263 | }
264 | catch(Exception ex){
265 | throw new TemplateConfigurationException("Unable to load the xipton.razor configuration. {0}. Please correct your xipton.razor configuration. Take a look at the inner exception(s) for details.".FormatWith(ex.Message),ex);
266 | }
267 |
268 | }
269 | private void LoadDefaults() {
270 | RootOperator = ConfigElement.Create();
271 | Templates = ConfigElement.Create();
272 | Namespaces = CreateDefaultNamespaces();
273 | References = CreateDefaultReferences();
274 | ContentProviders = CreateDefaultContentProviders();
275 | }
276 | private void TryResolveWildcardReferences()
277 | {
278 |
279 | // ensure xipton assemblies to be loaded in the execution context
280 | AppDomain.CurrentDomain
281 | .EnsureXiptonAssembliesLoaded();
282 |
283 | if (!References.Any(s => s.Contains("*.")))
284 | {
285 | // no need to resolve references
286 | return;
287 | }
288 |
289 | if (!_allowWildcardReferences)
290 | {
291 | throw new TemplateConfigurationException("AllowWildcardReferences == false -> References cannot be configured using wildcards. All references must be configured explicitely.");
292 | }
293 |
294 | // ensure all bin assemblies to be loaded in the execution context
295 | AppDomain.CurrentDomain.EnsureBinAssembliesLoaded();
296 |
297 | var domainAssemblies = AppDomain.CurrentDomain
298 | .GetAssemblies()
299 | .Where(a => !a.IsDynamic)
300 | .ToList();
301 |
302 | var referencedAssemblyFileNames = new List();
303 |
304 | FindAssemblyFileNamesByPattern("*.dll", domainAssemblies, referencedAssemblyFileNames);
305 | FindAssemblyFileNamesByPattern("*.exe", domainAssemblies, referencedAssemblyFileNames);
306 |
307 | References =
308 | References
309 | .Where(referenceName =>
310 | !referenceName.Contains("*") &&
311 | !referencedAssemblyFileNames.Any(filename => filename
312 | .TrimEnd()
313 | .EndsWith(EnsureLeadingBackSlash(referenceName), StringComparison.OrdinalIgnoreCase)
314 | )
315 | )
316 | .Concat(
317 | referencedAssemblyFileNames
318 | )
319 | .ToList()
320 | .AsReadOnly();
321 | }
322 | private void FindAssemblyFileNamesByPattern(string pattern, IEnumerable domainAssemblies, List referencedAssemblyFileNames){
323 | if (References.Contains(pattern, StringComparer.OrdinalIgnoreCase)) {
324 | // if the configuration contains any entry, then all collected DLLs are added to the referenced assemblies set
325 | referencedAssemblyFileNames.AddRange(
326 | domainAssemblies
327 | .Select(assembly => assembly.GetFileName())
328 | .Where(filename => filename.EndsWith(pattern.Substring(1), StringComparison.OrdinalIgnoreCase))
329 | );
330 | }
331 | }
332 | private static string EnsureLeadingBackSlash(string referenceName){
333 | if (referenceName == null) throw new ArgumentNullException("referenceName");
334 | return referenceName.Contains("\\") ? referenceName : "\\" + referenceName;
335 | }
336 |
337 | #endregion
338 |
339 |
340 | }
341 |
342 | }
343 |
344 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Config/RootOperatorElement.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System.Xml.Linq;
9 |
10 | namespace Xipton.Razor.Config
11 | {
12 | public class RootOperatorElement : ConfigElement {
13 |
14 | public string Path { get; internal set; }
15 |
16 | #region Overrides
17 | protected override void Load(XElement e) {
18 | Path = e.GetAttributeValue("path");
19 | }
20 |
21 | protected internal override void SetDefaults() {
22 | Path = "/";
23 | }
24 | #endregion
25 | }
26 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Config/TemplateConfigurationException.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 | using System.Runtime.Serialization;
10 | using Xipton.Razor.Core;
11 |
12 | namespace Xipton.Razor.Config
13 | {
14 | [Serializable]
15 | public class TemplateConfigurationException : TemplateException
16 | {
17 |
18 | public TemplateConfigurationException()
19 | {
20 | }
21 |
22 | public TemplateConfigurationException(string message) : base(message)
23 | {
24 | }
25 |
26 | public TemplateConfigurationException(string message, Exception inner) : base(message, inner)
27 | {
28 | }
29 |
30 | protected TemplateConfigurationException(
31 | SerializationInfo info,
32 | StreamingContext context) : base(info, context)
33 | {
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Config/TemplatesElement.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 | using System.Diagnostics;
10 | using System.Web.Razor;
11 | using System.Xml.Linq;
12 | using Xipton.Razor.Core.Generator;
13 | using Xipton.Razor.Core.Generator.CSharp;
14 | using Xipton.Razor.Core.Generator.VB;
15 | using Xipton.Razor.Extension;
16 |
17 | namespace Xipton.Razor.Config
18 | {
19 | public class TemplatesElement : ConfigElement {
20 |
21 | private Type
22 | _baseType;
23 | private RazorCodeLanguage
24 | _language;
25 |
26 |
27 | #region Properties
28 | ///
29 | /// Gets or sets the template's default base type. This settings can be overridden by the @inherits directive (Razor C#)
30 | ///
31 | ///
32 | /// The default type of the template base.
33 | ///
34 | /// The type set must be an open generic type, that inherits a subclass of . Also this type
35 | /// must have the same name as it's base type. So you need to implement two levels of custom base classes if you want
36 | /// to set this attribute.
37 | ///
38 | /// If you want to implement a custom base class named MyTemplateBase you need this class to inherit TemplateBase and add your custom implementation.
39 | /// Next you create a class named MyTemplateBase<TModel> like:
40 | ///
41 | /// public class MyTemplateBase<TModel> : MyTemplateBase, ITemplate<TModel>
42 | /// {
43 | /// public new TModel Model { get { return GetOrCreateModel<TModel>(); } }
44 | /// }
45 | ///
46 | ///
47 | ///
48 | ///
49 | public Type BaseType {
50 | get { return _baseType; }
51 | internal set {
52 | if (value == null) throw new ArgumentNullException("value");
53 | ValidateBaseType(value);
54 | _baseType = value;
55 | }
56 | }
57 | public RazorCodeLanguage Language {
58 | get { return _language; }
59 | internal set {
60 | _language = value
61 | .CastTo() // must be a Xipton implementation => else an exception is thrown here
62 | .CastTo();
63 | }
64 | }
65 | public string DefaultExtension { get; internal set; }
66 | public string AutoIncludeName { get; internal set; }
67 | public string SharedLocation { get; internal set; }
68 | public bool IncludeGeneratedSourceCode { get; internal set; }
69 | public bool HtmlEncode { get; internal set; }
70 |
71 | public string NonGenericBaseTypeName {
72 | get {
73 | var fullname = BaseType.FullName;
74 | var index = fullname == null ? -1 : fullname.IndexOf('`');
75 | Debug.Assert(fullname != null, "fullname != null");
76 | return index < 0 ? fullname : fullname.Substring(0, index);
77 | }
78 | }
79 | #endregion
80 |
81 | #region Overrides
82 | protected override void Load(XElement e) {
83 | var typeName = e.GetAttributeValue("language", false);
84 | if (typeName != null) {
85 | if (typeName.Equals("C#", StringComparison.OrdinalIgnoreCase))
86 | // convenient name for default C# implementation
87 | Language = new XiptonCSharpCodeLanguage();
88 | else if (typeName.Equals("VB", StringComparison.OrdinalIgnoreCase))
89 | // convenient name for default VB implementation
90 | Language = new XiptonVBCodeLanguage();
91 | else
92 | Language = Type.GetType(typeName, true).CreateInstance().CastTo();
93 | }
94 |
95 | typeName = e.GetAttributeValue("baseType", false);
96 | BaseType = typeName != null ? Type.GetType(typeName, true) : BaseType;
97 |
98 | DefaultExtension = (e.GetAttributeValue("defaultExtension", false) ?? DefaultExtension).EmptyAsNull();
99 | AutoIncludeName = (e.GetAttributeValue("autoIncludeName", false) ?? AutoIncludeName).EmptyAsNull();
100 | SharedLocation = (e.GetAttributeValue("sharedLocation", false) ?? SharedLocation).EmptyAsNull();
101 | var setting = e.GetAttributeValue("includeGeneratedSourceCode", false);
102 | if (setting != null)
103 | IncludeGeneratedSourceCode = bool.Parse(setting);
104 | setting = e.GetAttributeValue("htmlEncode", false);
105 | if (setting != null)
106 | HtmlEncode = bool.Parse(setting);
107 | }
108 | protected internal override void SetDefaults() {
109 | BaseType = typeof(TemplateBase);
110 | Language = new XiptonCSharpCodeLanguage();
111 | AutoIncludeName = "_viewStart";
112 | DefaultExtension = ".cshtml";
113 | SharedLocation = "~/Shared";
114 | IncludeGeneratedSourceCode = false;
115 | HtmlEncode = true;
116 | }
117 | #endregion
118 |
119 | private static void ValidateBaseType(Type baseType) {
120 |
121 | if (!baseType.IsGenericType) {
122 | try {
123 | baseType = baseType.Assembly.GetType(baseType.FullName + "`1", true); // => generic type must be defined as well
124 | }
125 | catch (Exception ex) {
126 | throw new TemplateConfigurationException("BaseType {0} must have a generic sub class with one type parameter.".FormatWith(baseType.FullName), ex);
127 | }
128 | }
129 |
130 | if (!baseType.IsGenericTypeDefinition || baseType.GetGenericArguments().Length != 1)
131 | throw new TemplateConfigurationException("BaseType must be an open generic type (or have a subclass that is a generic type) with one generic parameter (for TModel).");
132 |
133 | if (baseType.BaseType == null || baseType.BaseType.IsGenericType || !typeof(TemplateBase).IsAssignableFrom(baseType.BaseType))
134 | throw new TemplateConfigurationException("BaseType must inherit a non generic (custom) basetype that must be a subclass of {0}.".FormatWith(typeof(TemplateBase)));
135 |
136 | if (baseType.BaseType.Name != baseType.Name.Substring(0, baseType.Name.Length - 2))
137 | throw new TemplateConfigurationException("BaseType must be a generic type and must inherit a non generic basetype with the same name.");
138 | }
139 |
140 | }
141 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Config/XElementExtension.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Linq;
11 | using System.Xml.Linq;
12 | using Xipton.Razor.Extension;
13 |
14 | namespace Xipton.Razor.Config {
15 |
16 | internal static class XElementExtension {
17 |
18 | public static string GetAttributeValue(this XElement element, string name, bool required = true) {
19 | var attribute = element == null ? null : element.Attribute(XName.Get(name));
20 | if (attribute == null) {
21 | if (required && element != null)
22 | throw new TemplateConfigurationException("required attribute '{0}' missing at element '{1}'.".FormatWith(name, element.Name));
23 | return null;
24 | }
25 | return attribute.Value;
26 | }
27 |
28 | // convenience implementation for fluency reasons and being able to report a clear configuration error
29 | public static XElement SingleOrDefault(this IEnumerable elements, XElement defaultValue) {
30 | if (elements == null) return defaultValue;
31 | var xElements = elements as XElement[] ?? elements.ToArray();
32 | if (xElements.Length == 0)
33 | return defaultValue;
34 | if (xElements.Length > 1)
35 | throw new TemplateConfigurationException("More that one element named '{0}' found at your configuration.".FormatWith(xElements.First().Name));
36 | return xElements[0];
37 | }
38 |
39 | public static bool HasClearChildElement(this IEnumerable root, string parentName) {
40 | if (root == null) throw new ArgumentNullException("root");
41 | if (parentName == null) throw new ArgumentNullException("parentName");
42 | return root
43 | .Descendants(parentName)
44 | .SingleOrDefault(new XElement(parentName))
45 | .Descendants("clear")
46 | .SingleOrDefault() != null;
47 |
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Config/XmlConfigurationSection.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System.Configuration;
9 | using System.Xml;
10 | using System.Xml.Linq;
11 |
12 | namespace Xipton.Razor.Config {
13 | ///
14 | /// General purpose configuration section. The whole section's inner xml is loaded without any validation.
15 | ///
16 | public class XmlConfigurationSection : ConfigurationSection
17 | {
18 | private bool _firstUnrecognizedElementHandled;
19 |
20 | public XElement InnerXml { get; private set; }
21 |
22 | protected override bool OnDeserializeUnrecognizedElement(string elementName, XmlReader reader) {
23 | if (!_firstUnrecognizedElementHandled){
24 | _firstUnrecognizedElementHandled = true;
25 | InnerXml = (XElement) XNode.ReadFrom(reader);
26 | }
27 | else{
28 | throw new ConfigurationErrorsException("The XmlConfigurationSection must contain at most one child element (holding as many grand childs as you like).");
29 | }
30 | return true;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Config/xipton.razor.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Core/ContentManager.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 | using System.Collections.Concurrent;
10 | using System.Collections.Generic;
11 | using System.Linq;
12 | using System.Text;
13 | using Xipton.Razor.Config;
14 | using Xipton.Razor.Core.ContentProvider;
15 | using Xipton.Razor.Extension;
16 |
17 | namespace Xipton.Razor.Core
18 | {
19 | ///
20 | /// The ContentManager assembles content and delivers final content to the template factory. It implements additional routing logic on top of the content providers.
21 | ///
22 | public class ContentManager : IDisposable
23 | {
24 |
25 | #region Fields
26 | // if cached null results reaches this count then the cache is purged (null results are removed).
27 | // this is needed to prevent the cache from getting loaded endlessly with null results from invalid requests
28 | private const int _cacheMaxNullCount = 1000;
29 |
30 | private CompositeContentProvider
31 | _contentProvider;
32 |
33 | private int
34 | _nullNormalizedEntryCount,
35 | _nullResourceEntryCount;
36 |
37 |
38 | private readonly VirtualPathBuilder
39 | _pathBuilder;
40 |
41 | private readonly IList
42 | _virtualSearchPathList;
43 |
44 | private readonly ConcurrentDictionary
45 | _requestToResourceNameMap = new ConcurrentDictionary(),
46 | _resourceNameToVirtualPathMap = new ConcurrentDictionary(),
47 | _requestToVirtualTargetMap = new ConcurrentDictionary();
48 |
49 | private readonly string
50 | _autoIncludeName;
51 | private readonly string
52 | _defaultExtension;
53 | #endregion
54 |
55 | public event EventHandler SharedContentModified;
56 |
57 | public ContentManager(RazorConfig config)
58 | {
59 | if (config == null) throw new ArgumentNullException("config");
60 | config = config.AsReadonly();
61 | _contentProvider = new CompositeContentProvider();
62 | ContentProvider.ContentModified += OnContentModified;
63 | config.ContentProviders.ToList().ForEach(ctor => AddContentProvider(ctor()));
64 |
65 | _pathBuilder = new VirtualPathBuilder(config.RootOperator.Path);
66 | _autoIncludeName = config.Templates.AutoIncludeName.EmptyAsNull();
67 | _defaultExtension = config.Templates.DefaultExtension.EmptyAsNull();
68 | if (_autoIncludeName != null && !_autoIncludeName.Contains(".") && _defaultExtension != null)
69 | _autoIncludeName = _autoIncludeName + "." + _defaultExtension.TrimStart('.');
70 | var shared = config.Templates.SharedLocation.EmptyAsNull();
71 | var searchPathList = new List();
72 | if (shared != null)
73 | searchPathList.Add(GetPathBuilderWithRootOperator(shared).RemoveTrailingSlash());
74 | _virtualSearchPathList = searchPathList.AsReadOnly();
75 | }
76 |
77 | #region Content provider management
78 |
79 | public IContentProvider ContentProvider{
80 | get { return _contentProvider; }
81 | }
82 |
83 | public ContentManager AddContentProvider(IContentProvider contentProvider, int order = 0)
84 | {
85 | if (contentProvider == null) throw new ArgumentNullException("contentProvider");
86 | ContentProvider.CastTo().AddContentProvider(contentProvider, order);
87 | return this;
88 | }
89 |
90 | public ContentManager RemoveContentProviders(Type type)
91 | {
92 | ContentProvider.CastTo().RemoveContentProviders(type);
93 | return this;
94 | }
95 | public ContentManager RemoveContentProviders() where TContentProvider : IContentProvider {
96 | return RemoveContentProviders(typeof(TContentProvider));
97 | }
98 | public ContentManager RemoveContentProvider(IContentProvider provider) {
99 | ContentProvider.CastTo().RemoveContentProvider(provider);
100 | return this;
101 | }
102 |
103 | public IContentProvider TryGetContentProvider(Type contentProviderType)
104 | {
105 | return ContentProvider
106 | .CastTo()
107 | .TryGetContentProvider(contentProviderType);
108 | }
109 | public T TryGetContentProvider() where T : IContentProvider
110 | {
111 | return TryGetContentProvider(typeof(T))
112 | .CastTo();
113 | }
114 |
115 | public IEnumerable GetContentProviders(Type contentProviderType) {
116 | return ContentProvider
117 | .CastTo()
118 | .GetContentProviders(contentProviderType);
119 | }
120 | public IEnumerable GetContentProviders() where T : IContentProvider {
121 | return GetContentProviders(typeof (T)).Cast();
122 | }
123 |
124 | public ContentManager ClearAllContentProviders(){
125 | ContentProvider.CastTo().ClearAllContentProviders();
126 | return this;
127 | }
128 | #endregion
129 |
130 | ///
131 | /// Resolves a virtual path (i.e. an existing virtual path) for any incomming virtual request.
132 | /// example: a layout request like Layout="_layout" at template ~/templates/mytemplate.cshtml at first is attempted to get resolved at "~/templates/_layout.cshtml"
133 | /// But if the "_layout" only exists at "~/shared" this method translates the incomming request "~/templates/_layout.cshtml" into "~/shared/_layout.cshtml".
134 | ///
135 | ///
136 | /// Since searching at resources may need considarable amounts of time the map results are cached.
137 | /// If any content resource changes (notified by ) the whole mapping cache is cleared.
138 | ///
139 | /// The requested path.
140 | /// The actual virtual path or null if no resolve could be made
141 | public string TryGetVirtualPath(string requestedPath)
142 | {
143 | if (string.IsNullOrEmpty(requestedPath))
144 | return null;
145 |
146 | if (_nullNormalizedEntryCount > _cacheMaxNullCount) {
147 | // clear entries that gave a null result once in a while
148 | _nullNormalizedEntryCount = 0;
149 | string value;
150 | _requestToVirtualTargetMap
151 | .Where(x => x.Value == null)
152 | .ToList()
153 | .ForEach(x => _requestToVirtualTargetMap.TryRemove(x.Key, out value));
154 | }
155 |
156 | return _requestToVirtualTargetMap.GetOrAdd(requestedPath, path =>
157 | {
158 | var pathBuilder = GetPathBuilderWithRootOperator(path);
159 | pathBuilder.AddOrKeepExtension(_defaultExtension);
160 |
161 | var resourceName = ContentProvider.TryGetResourceName(pathBuilder);
162 | if (resourceName != null)
163 | // content was found at the requested virtual location
164 | return pathBuilder;
165 |
166 | // search all search paths for an actual virtual path
167 | var name = pathBuilder.GetLastPart(true);
168 | var result = VirtualSearchPathList.Any(searchPath => (resourceName = ContentProvider.TryGetResourceName(pathBuilder.Clear().CombineWith(searchPath, name))) != null) ? pathBuilder : null;
169 | if (result == null)
170 | _nullNormalizedEntryCount++;
171 | return result;
172 | });
173 | }
174 |
175 | ///
176 | /// Try to reolve a virtual request into a resource name (e.g. a filename).
177 | ///
178 | ///
179 | /// Since searching in resources may need considarable amounts of time the results are cached.
180 | /// If any content resource changes (notified by ) the whole cache is cleared.
181 | ///
182 | /// The requested path.
183 | /// The targeted resource name, or null if no resource name was found
184 | public string TryGetResourceName(string requestedPath)
185 | {
186 | if (string.IsNullOrEmpty(requestedPath))
187 | return null;
188 |
189 | if (_nullResourceEntryCount > _cacheMaxNullCount) {
190 | _nullResourceEntryCount = 0;
191 | string value;
192 | _requestToResourceNameMap
193 | .Where(x => x.Value == null)
194 | .ToList()
195 | .ForEach(x => _requestToResourceNameMap.TryRemove(x.Key, out value));
196 | }
197 |
198 | return _requestToResourceNameMap
199 | .GetOrAdd(requestedPath, path =>
200 | {
201 | var virtualLocation = TryGetVirtualPath(path);
202 | var resourceName = virtualLocation == null ? null : ContentProvider.TryGetResourceName(virtualLocation);
203 | if(resourceName != null)
204 | _resourceNameToVirtualPathMap[resourceName] = virtualLocation;
205 | else
206 | _nullResourceEntryCount++;
207 | return resourceName;
208 | });
209 | }
210 |
211 | ///
212 | /// Try to resolve, read and return the content by the requested path.
213 | /// All includes (respresented by AutoIncludeName e.g. _viewStart) from the
214 | /// current folder until te virtual root folder are inserted as well.
215 | /// The nearest include is inserted as the last, so the nearest include
216 | /// defines any possible override (e.g. Layout setting).
217 | ///
218 | ///
219 | /// The content itself is never cached.
220 | ///
221 | /// The requested path.
222 | /// The content or null if no content was found
223 | public string TryGetContent(string requestedPath)
224 | {
225 | var resourceName = TryGetResourceName(requestedPath);
226 | if (resourceName == null)
227 | return null;
228 |
229 | var content = ContentProvider.TryGetContent(resourceName);
230 | if (content == null || _autoIncludeName == null)
231 | return content;
232 |
233 | var virtualPath = TryGetVirtualPath(requestedPath);
234 |
235 | var sb = new StringBuilder(content);
236 | var nearestInclude = _pathBuilder
237 | .New()
238 | .CombineWith(virtualPath)
239 | .RemoveLastPart()
240 | .CombineWith(_autoIncludeName)
241 | .AddOrKeepExtension(_defaultExtension);
242 |
243 | var includes = FindAutoIncludes(nearestInclude).ToList();
244 |
245 | foreach (var include in includes)
246 | {
247 | //sb.Insert(0, Environment.NewLine);
248 | sb.Insert(0, ContentProvider.TryGetContent(include));
249 | }
250 | return sb.ToString();
251 | }
252 |
253 | ///
254 | /// Gets the search path list as a read only list. Normally this list has one entry.
255 | ///
256 | public IList VirtualSearchPathList
257 | {
258 | get { return _virtualSearchPathList; }
259 | }
260 |
261 | #region Implementation of IDisposable
262 |
263 | public void Dispose()
264 | {
265 | Dispose(true);
266 | }
267 | protected virtual void Dispose(bool disposing)
268 | {
269 | if (!disposing) return;
270 | var provider = _contentProvider;
271 | _contentProvider = null;
272 | if (provider == null) return;
273 | provider.ContentModified -= OnContentModified;
274 | provider.Dispose();
275 | }
276 |
277 | #endregion
278 |
279 | #region Private
280 | private IEnumerable FindAutoIncludes(string virtualPathToNearestAutoInclude)
281 | {
282 | var vp = GetPathBuilderWithRootOperator(virtualPathToNearestAutoInclude);
283 |
284 | vp.AddOrKeepExtension(_defaultExtension);
285 |
286 | var actual = ContentProvider.TryGetResourceName(vp);
287 | if (actual != null)
288 | yield return actual;
289 |
290 | var name = vp.GetLastPart(true);
291 | var searchPathes = VirtualSearchPathList;
292 | while (!searchPathes.Contains(vp.RemoveTrailingSlash(),StringComparer.OrdinalIgnoreCase) && vp.RemoveLastPart().Length != 0)
293 | {
294 | // search all parents until the virtual root, or until any shared folder name
295 | actual = ContentProvider.TryGetResourceName(vp.CombineWith(name));
296 | if (actual != null) yield return actual;
297 | vp.RemoveLastPart();
298 | }
299 | }
300 | private VirtualPathBuilder GetPathBuilderWithRootOperator(string path)
301 | {
302 | return _pathBuilder.New().CombineWith(path).Normalize().WithRootOperator();
303 | }
304 | private void OnContentModified(object sender, ContentModifiedArgs e)
305 | {
306 | _requestToResourceNameMap.Clear();
307 | _requestToVirtualTargetMap.Clear();
308 |
309 | if (SharedContentModified == null) return;
310 |
311 | string virtualLocation;
312 | if (!_resourceNameToVirtualPathMap.TryGetValue(e.ModifiedResourceName, out virtualLocation)){
313 | if (_autoIncludeName != null && e.ModifiedResourceName.ToLower().Contains(_autoIncludeName.ToLower())){
314 | // extra check to force clearing type cache of no _viewStart has been requested until now
315 | SharedContentModified(this, new ContentModifiedArgs(e.ModifiedResourceName));
316 | }
317 | return;
318 | }
319 |
320 | var modifiedName = _pathBuilder
321 | .New()
322 | .CombineWith(virtualLocation)
323 | .AddOrKeepExtension(_defaultExtension)
324 | .GetLastPart(true);
325 |
326 | if (string.Equals(modifiedName, _autoIncludeName, StringComparison.OrdinalIgnoreCase))
327 | {
328 | // If the name equals _autoIncludeName (like _viewStart) notify listeners. Such content is included in all generated source. Normally as a result the whole type cache needs to be cleared.
329 | SharedContentModified(this, new ContentModifiedArgs(e.ModifiedResourceName));
330 | }
331 | }
332 | #endregion
333 |
334 | }
335 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Core/ContentModifiedArgs.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 |
10 | namespace Xipton.Razor.Core
11 | {
12 | public class ContentModifiedArgs : EventArgs
13 | {
14 | public ContentModifiedArgs(string modifiedResourceName)
15 | {
16 | if (modifiedResourceName == null) throw new ArgumentNullException("modifiedResourceName");
17 | ModifiedResourceName = modifiedResourceName;
18 | }
19 |
20 | public string ModifiedResourceName { get; private set; }
21 | }
22 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Core/ContentProvider/CompositeContentProvider.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Linq;
11 | using System.Xml.Linq;
12 | using Xipton.Razor.Extension;
13 |
14 | namespace Xipton.Razor.Core.ContentProvider
15 | {
16 | ///
17 | /// The CompositeContentProvider behaves like an IContentProvider, and holds
18 | /// an inner list of (one or more) specific IContentProvider implementations that were registered by .
19 | /// The first inner registered IContentProvider that has a valid response to a request returns the result.
20 | /// So requests for different virtual path names may be handled by different content providers.
21 | ///
22 | /// You cannot explicitly map (or route) virtual path names to specific content providers here. The first content provider that has
23 | /// a valid result on any request holds. But you can control the order in which the inner specific content providers
24 | /// are invoked, and so manage the provider priority. e.g. you could add a file provider first followed by an embedded
25 | /// resource provider. As a result you can work with content as embedded resources unless you create a file that is resolved
26 | /// by a same virtual path as any embedded resource. In that case the file content is returned because it is found first thus
27 | /// giving you the possibility to replace or customize embedded resources (e.g. layouts) by file content simply by creating
28 | /// templates (layouts) at a file location that is resolved by the same virtual path name.
29 | ///
30 | internal sealed class CompositeContentProvider : IContentProvider, IDisposable
31 | {
32 | //now order matters no dictionary is applied here
33 | private readonly List
34 | _contentProviders = new List();
35 |
36 | #region Implementation of IContentProvider
37 |
38 | public event EventHandler ContentModified;
39 |
40 | public string TryGetResourceName(string virtualPath)
41 | {
42 | lock(_contentProviders)
43 | {
44 | return _contentProviders
45 | .Select(provider => provider.TryGetResourceName(virtualPath)).FirstOrDefault(s => s != null);
46 | }
47 | }
48 |
49 | public string TryGetContent(string resourceName)
50 | {
51 | lock (_contentProviders)
52 | {
53 | return _contentProviders
54 | .Select(provider => provider.TryGetContent(resourceName)).FirstOrDefault(s => s != null);
55 | }
56 | }
57 |
58 | public IContentProvider InitFromConfig(XElement element){
59 | throw new NotImplementedException("The composite cannot be initialized by configuration directly (attempted by '{0}'). Instead for all individual childs (specific content providers) constructors are created at the GeneratorConfig class.".FormatWith(element));
60 | }
61 |
62 | #endregion
63 |
64 | public CompositeContentProvider AddContentProvider(IContentProvider contentProvider, int order = 0)
65 | {
66 | if (contentProvider == null) throw new ArgumentNullException("contentProvider");
67 | lock (_contentProviders)
68 | {
69 | contentProvider.ContentModified += OnContentModified;
70 | if (order < _contentProviders.Count && order >= 0)
71 | _contentProviders.Insert(order, contentProvider);
72 | else
73 | _contentProviders.Add(contentProvider);
74 | return this;
75 | }
76 | }
77 |
78 | public CompositeContentProvider RemoveContentProvider(IContentProvider contentProvider) {
79 | if (contentProvider == null) return this;
80 | lock (_contentProviders){
81 | if (_contentProviders.Remove(contentProvider)){
82 | contentProvider.ContentModified -= OnContentModified;
83 | contentProvider.TryDispose();
84 | }
85 | }
86 | return this;
87 | }
88 |
89 | public CompositeContentProvider RemoveContentProviders(Type type)
90 | {
91 | lock (_contentProviders){
92 | foreach (var provider in _contentProviders.ToList().Where(provider => provider.GetType() == type)){
93 | RemoveContentProvider(provider);
94 | }
95 | return this;
96 | }
97 | }
98 |
99 | public CompositeContentProvider ClearAllContentProviders(){
100 | lock(_contentProviders){
101 | _contentProviders.ForEach(p =>
102 | {
103 | p.ContentModified -= OnContentModified;
104 | p.TryDispose();
105 | });
106 | _contentProviders.Clear();
107 | return this;
108 | }
109 | }
110 |
111 | ///
112 | /// gets the content provider by its type. Throws an exception if more than one content providers have been registered for the same type
113 | ///
114 | /// The type.
115 | ///
116 | public IContentProvider TryGetContentProvider(Type type) {
117 | lock (_contentProviders){
118 | return _contentProviders.SingleOrDefault(p => p.GetType() == type);
119 | }
120 | }
121 |
122 | ///
123 | /// gets all content provider with the requested type.
124 | ///
125 | /// The type.
126 | ///
127 | public IEnumerable GetContentProviders(Type type) {
128 | lock (_contentProviders){
129 | return _contentProviders.Where(p => p.GetType() == type);
130 | }
131 | }
132 |
133 |
134 | private void OnContentModified(object sender, ContentModifiedArgs e)
135 | {
136 | if (ContentModified != null)
137 | {
138 | ContentModified(sender, e);
139 | }
140 | }
141 |
142 | #region Implementation of IDisposable
143 |
144 | public void Dispose()
145 | {
146 | ClearAllContentProviders();
147 | }
148 |
149 | #endregion
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Core/ContentProvider/EmbeddedResourceContentProvider.cs:
--------------------------------------------------------------------------------
1 | // disable warning "Event is never used"
2 | // justification: event is part of interface and therefore must be declared.
3 | #pragma warning disable 67
4 |
5 | #region Microsoft Public License
6 | /* This code is part of Xipton.Razor v3.0
7 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
8 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
9 | */
10 | #endregion
11 |
12 |
13 | using System;
14 | using System.IO;
15 | using System.Linq;
16 | using System.Reflection;
17 | using System.Xml.Linq;
18 | using Xipton.Razor.Config;
19 | using Xipton.Razor.Extension;
20 |
21 | namespace Xipton.Razor.Core.ContentProvider
22 | {
23 | ///
24 | /// The EmbeddedResourceContentProvider provides content from razor templates that
25 | /// were compiled as embedded resources. It needs to know the assembly that holds the
26 | /// embedded templates so you must pass that assembly at the constructor together with
27 | /// the root namespace for all embedded resources.
28 | ///
29 | public class EmbeddedResourceContentProvider : IContentProvider
30 | {
31 | private Assembly _resourceAssembly;
32 | private string _rootNameSpace;
33 |
34 | protected EmbeddedResourceContentProvider(){}
35 |
36 | public EmbeddedResourceContentProvider(Assembly resourceAssembly, string rootNameSpace)
37 | {
38 | if (resourceAssembly == null) throw new ArgumentNullException("resourceAssembly");
39 | if (rootNameSpace == null) throw new ArgumentNullException("rootNameSpace");
40 | _resourceAssembly = resourceAssembly;
41 | _rootNameSpace = rootNameSpace;
42 | }
43 |
44 | #region Implementation of IContentProvider
45 |
46 | public event EventHandler ContentModified;
47 |
48 | public string TryGetResourceName(string virtualPath)
49 | {
50 | if (virtualPath.NullOrEmpty()) return null;
51 | var resourceName = _rootNameSpace + "." + virtualPath.RemoveRoot().Replace("/",".").Replace("-","_");
52 | var resources = _resourceAssembly.GetManifestResourceNames().ToList();
53 | return resources.FirstOrDefault(r => AreEqualResourceNames(r, resourceName));
54 | }
55 |
56 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times", Justification = "The stream can be disposed multiple times.")]
57 | public string TryGetContent(string resourceName)
58 | {
59 | using (var stream = _resourceAssembly.GetManifestResourceStream(resourceName))
60 | {
61 | if (stream == null) return null;
62 | using (var sr = new StreamReader(stream))
63 | return sr.ReadToEnd();
64 | }
65 | }
66 |
67 | public IContentProvider InitFromConfig(XElement element){
68 | var resourceAssembly = element.GetAttributeValue("resourceAssembly", false);
69 | if (resourceAssembly != null)
70 | _resourceAssembly = AppDomain.CurrentDomain.GetOrLoadAssembly(resourceAssembly);
71 | _rootNameSpace = element.GetAttributeValue("rootNameSpace", false) ?? _rootNameSpace;
72 | if (_resourceAssembly == null) throw new TemplateConfigurationException("{0}: attribute resourceAssembly is required and not allowed null".FormatWith(element));
73 | if (_rootNameSpace == null) throw new TemplateConfigurationException("{0}: attribute rootNameSpace is required and not allowed null".FormatWith(element));
74 | return this;
75 | }
76 |
77 |
78 |
79 | #endregion
80 |
81 | private static bool AreEqualResourceNames(string s1, string resourceName)
82 | {
83 | if (s1 == null || resourceName == null) return s1 == null && resourceName == null;
84 | if (s1.Length != resourceName.Length)
85 | return false;
86 | s1 = s1.Replace("-", "_");
87 | return string.Compare(s1, resourceName, StringComparison.OrdinalIgnoreCase) == 0;
88 | }
89 |
90 |
91 |
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Core/ContentProvider/FileContentProvider.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 | using System.IO;
10 | using System.Security.Permissions;
11 | using System.Xml.Linq;
12 | using Xipton.Razor.Config;
13 | using Xipton.Razor.Extension;
14 |
15 | namespace Xipton.Razor.Core.ContentProvider
16 | {
17 | ///
18 | /// The FileContentProvider provides content from files requested by virtual path names.
19 | /// A FileWatcher is created to monitor and publish file changes.
20 | ///
21 | [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] // needed because of the file watcher events
22 | [SecurityPermission(SecurityAction.InheritanceDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] // needed because of the file watcher events, needed for notification on sub classing
23 | public class FileContentProvider : IContentProvider, IDisposable
24 | {
25 | #region Fields
26 | private string
27 | _rootFolder = ".".MakeAbsoluteDirectoryPath();
28 |
29 | private FileSystemWatcher
30 | _watcher;
31 |
32 | private readonly object
33 | _syncRoot = new object();
34 | #endregion
35 |
36 | protected FileContentProvider() {}
37 |
38 | ///
39 | /// Initializes a new instance of the class.
40 | /// It needs the root directory of where the content folders start. Normally this is the application's
41 | /// base folder, or something like [basefolder]/Views
42 | ///
43 | /// The root directory.
44 | public FileContentProvider(string rootFolder)
45 | {
46 | _rootFolder = new DirectoryInfo(rootFolder.MakeAbsoluteDirectoryPath()).FullName;
47 | }
48 |
49 | #region Implementation of IContentProvider
50 |
51 | public event EventHandler ContentModified;
52 |
53 | public virtual string TryGetResourceName(string virtualPath)
54 | {
55 | if (string.IsNullOrEmpty(virtualPath)) return null;
56 | var file = new FileInfo(Path.Combine(_rootFolder, virtualPath.RemoveRoot()).Replace('/', Path.DirectorySeparatorChar));
57 | if (!file.Exists) return null;
58 | EnsureWatcherInitialized();
59 | return file.FullName;
60 | }
61 |
62 | public virtual string TryGetContent(string resourceFileName){
63 | return !File.Exists(resourceFileName) ? null : File.ReadAllText(resourceFileName);
64 | }
65 |
66 | public virtual IContentProvider InitFromConfig(XElement element){
67 | var rootFolder = (element.GetAttributeValue("rootFolder", false) ?? _rootFolder).MakeAbsoluteDirectoryPath();
68 | _rootFolder = new DirectoryInfo(rootFolder).FullName;
69 | return this;
70 | }
71 |
72 | #endregion
73 |
74 | #region Implementation of IDisposable
75 | public void Dispose()
76 | {
77 | Dispose(true);
78 | }
79 | protected virtual void Dispose(bool disposing)
80 | {
81 | lock (_syncRoot)
82 | {
83 | if (disposing && _watcher != null)
84 | {
85 | _watcher.EnableRaisingEvents = false;
86 | _watcher.Changed -= OnChanged;
87 | _watcher.Deleted -= OnChanged;
88 | _watcher.Renamed -= OnRenamed;
89 | _watcher.Dispose();
90 | _watcher = null;
91 | }
92 | }
93 | }
94 | #endregion
95 |
96 | #region FileWatcher
97 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "_watcher is disposed on FileContentProvider.Dispose()")]
98 | private void EnsureWatcherInitialized()
99 | {
100 | lock (_syncRoot)
101 | {
102 | if (_watcher != null || ContentModified == null) return;
103 |
104 | _watcher = new FileSystemWatcher
105 | {
106 | Path = _rootFolder,
107 | NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.LastAccess,
108 | Filter = "*.*",
109 | IncludeSubdirectories = true
110 | };
111 |
112 | _watcher.Changed += OnChanged;
113 | _watcher.Deleted += OnChanged;
114 | _watcher.Renamed += OnRenamed;
115 | _watcher.Created += OnChanged;
116 | _watcher.EnableRaisingEvents = true;
117 | }
118 | }
119 |
120 | private void OnRenamed(object sender, RenamedEventArgs e)
121 | {
122 | if (ContentModified != null)
123 | ContentModified(this, new ContentModifiedArgs(e.OldFullPath));
124 | }
125 |
126 | private void OnChanged(object sender, FileSystemEventArgs e)
127 | {
128 | if (ContentModified != null)
129 | ContentModified(this, new ContentModifiedArgs(e.FullPath));
130 | }
131 |
132 | #endregion
133 |
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Core/ContentProvider/MemoryContentProvider.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 | using System.Linq;
10 | using System.Collections.Generic;
11 | using System.Xml.Linq;
12 |
13 | namespace Xipton.Razor.Core.ContentProvider
14 | {
15 | ///
16 | /// Provides in memory registration of content by its virtual path name with
17 | ///
18 | public class MemoryContentProvider : IContentProvider
19 | {
20 | private readonly Dictionary
21 | _content = new Dictionary(StringComparer.OrdinalIgnoreCase);
22 |
23 | #region Implementation of IContentProvider
24 |
25 | public event EventHandler ContentModified;
26 |
27 | public string TryGetResourceName(string virtualPath)
28 | {
29 | lock (_content)
30 | {
31 | return virtualPath != null && _content.ContainsKey(virtualPath) ? virtualPath : null;
32 | }
33 | }
34 |
35 | public string TryGetContent(string resourceName)
36 | {
37 | lock (_content)
38 | {
39 | string content;
40 | return resourceName != null && _content.TryGetValue(resourceName, out content) ? content : null;
41 | }
42 | }
43 |
44 | public IContentProvider InitFromConfig(XElement element){
45 | return this;
46 | }
47 |
48 | #endregion
49 |
50 | public Dictionary GetRegisteredTemplates(){
51 | return _content.ToDictionary(item => item.Key, item => item.Value);
52 | }
53 |
54 | public MemoryContentProvider RemoveTemplate(string virtualRootRelativePath){
55 | return RegisterTemplate(virtualRootRelativePath, null);
56 | }
57 |
58 | public MemoryContentProvider RegisterTemplate(string virtualRootRelativePath, string content)
59 | {
60 | lock (_content)
61 | {
62 | var notify = ContentModified != null && _content.ContainsKey(virtualRootRelativePath);
63 |
64 | if (content == null)
65 | _content.Remove(virtualRootRelativePath);
66 | else
67 | _content[virtualRootRelativePath] = content;
68 |
69 | if (notify)
70 | ContentModified(this, new ContentModifiedArgs(virtualRootRelativePath));
71 | }
72 | return this;
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Core/DynamicData.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 | using System.Collections;
10 | using System.Collections.Concurrent;
11 | using System.Collections.Generic;
12 | using System.Dynamic;
13 | using System.Linq;
14 | using System.Runtime.CompilerServices;
15 |
16 | namespace Xipton.Razor.Core
17 | {
18 | ///
19 | /// This class is used for both the template's Model (with anonymous model types only) and ViewBag property
20 | ///
21 | public class DynamicData : DynamicObject
22 | {
23 | private readonly ConcurrentDictionary
24 | _data;
25 |
26 | public DynamicData(object target)
27 | : this(target == null ? null : (IDictionary)target.GetType()
28 | .GetProperties()
29 | .Where(property => property.CanRead && property.GetIndexParameters().Length == 0)
30 | .ToDictionary(property => property.Name, property => property.GetValue(target, null)))
31 | {
32 | }
33 |
34 | public DynamicData(IDictionary data)
35 | {
36 | _data = new ConcurrentDictionary();
37 | if (data == null)
38 | return;
39 |
40 | foreach (var key in data.Keys)
41 | _data[key.ToString()] = ToDynamic(data[key]);
42 | }
43 |
44 | public DynamicData(IEnumerable> data = null)
45 | {
46 | _data = new ConcurrentDictionary();
47 | if (data != null)
48 | foreach (var pair in data)
49 | _data[pair.Key] = ToDynamic(pair.Value);
50 | }
51 |
52 | ///
53 | /// The model only needs to be wrapped into a IDynamicMetaObjectProvider if it is an emitted anonymous type.
54 | ///
55 | /// The model.
56 | ///
57 | public static dynamic ToDynamic(object model) {
58 | return model == null || !Attribute.IsDefined(model.GetType(), typeof(CompilerGeneratedAttribute))
59 | ? model
60 | : (model is IDynamicMetaObjectProvider
61 | ? model
62 | : new DynamicData(model));
63 | }
64 |
65 |
66 | public override IEnumerable GetDynamicMemberNames()
67 | {
68 | return _data.Keys;
69 | }
70 |
71 | public override bool TryGetMember(GetMemberBinder binder, out object result)
72 | {
73 | return _data.TryGetValue(binder.Name, out result);
74 | }
75 |
76 | public override bool TrySetMember(SetMemberBinder binder, object value)
77 | {
78 | _data[binder.Name] = ToDynamic(value);
79 | return true;
80 | }
81 |
82 |
83 | }
84 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Core/Generator/CSharp/XiptonCSharpCodeLanguage.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System.Web.Razor;
9 | using System.Web.Razor.Parser;
10 |
11 | namespace Xipton.Razor.Core.Generator.CSharp
12 | {
13 | public class XiptonCSharpCodeLanguage : CSharpRazorCodeLanguage, IXiptonCodeLanguage
14 | {
15 | public override ParserBase CreateCodeParser()
16 | {
17 | return new XiptonCSharpCodeParser();
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Core/Generator/CSharp/XiptonCSharpCodeParser.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System.Web.Razor.Parser;
9 |
10 | namespace Xipton.Razor.Core.Generator.CSharp
11 | {
12 | ///
13 | /// This C# CodeParser is extended for being able to handle the @model directive
14 | ///
15 | public class XiptonCSharpCodeParser : CSharpCodeParser
16 | {
17 |
18 | private static class Constants
19 | {
20 | public const string ModelKeyword = "model";
21 | public const string ParseErrorInheritsKeywordMustBeFollowedByTypeName = "The 'model' keyword must be followed by a type name on the same line.";
22 | }
23 | public XiptonCSharpCodeParser()
24 | {
25 | MapDirectives(ModelDirective, new[]{Constants.ModelKeyword});
26 | }
27 |
28 | protected virtual void ModelDirective()
29 | {
30 | AcceptAndMoveNext();
31 | ModelDirectiveCore();
32 | }
33 |
34 | protected void ModelDirectiveCore()
35 | {
36 | BaseTypeDirective(Constants.ParseErrorInheritsKeywordMustBeFollowedByTypeName, modelType => new SetModelCodeGenerator(modelType));
37 | }
38 |
39 | }
40 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Core/Generator/IXiptonCodeLanguage.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | namespace Xipton.Razor.Core.Generator
9 | {
10 |
11 | ///
12 | /// Marker interface for Xipton CodeLanguages
13 | ///
14 | public interface IXiptonCodeLanguage
15 | {
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Core/Generator/SetModelCodeGenerator.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 | using System.CodeDom;
10 | using System.Web.Razor;
11 | using System.Web.Razor.Generator;
12 | using System.Web.Razor.Parser.SyntaxTree;
13 | using Xipton.Razor.Extension;
14 |
15 | namespace Xipton.Razor.Core.Generator
16 | {
17 | ///
18 | /// SpanCodeGenerator for the model directive
19 | ///
20 | public class SetModelCodeGenerator : SpanCodeGenerator
21 | {
22 | public SetModelCodeGenerator(string modelType){
23 | ModelType = modelType;
24 | }
25 |
26 | public override void GenerateCode(Span target, CodeGeneratorContext context)
27 | {
28 | context.GeneratedClass.BaseTypes.Clear();
29 | context.GeneratedClass.BaseTypes.Add(new CodeTypeReference(ResolveType(context)));
30 |
31 | #region Work Around
32 | if (!(context.Host.CodeLanguage is VBRazorCodeLanguage))
33 | context.GeneratedClass.LinePragma = context.GenerateLinePragma(target, CalculateSpanPadding(target,0));
34 | //else
35 | // exclude VBRazorCodeLanguage
36 | // with VB I found a problem with the #End ExternalSource directive rendered at the GeneratedClass's end while it should not be rendered
37 | // this only effects the compile error report
38 |
39 | #endregion
40 | }
41 |
42 | //thanks to Marko Lahma
43 | private int CalculateSpanPadding(Span target, int generatedStart)
44 | {
45 | int num = target.Start.CharacterIndex - generatedStart;
46 | if (num < 0)
47 | num = 0;
48 | return num;
49 | }
50 |
51 | protected virtual string ResolveType(CodeGeneratorContext context)
52 | {
53 | var modelType = ModelType.Trim();
54 | if (context.Host.CodeLanguage is VBRazorCodeLanguage)
55 | return "{0}(Of {1})".FormatWith(context.Host.DefaultBaseClass, modelType);
56 | if (context.Host.CodeLanguage is CSharpRazorCodeLanguage)
57 | return "{0}<{1}>".FormatWith(context.Host.DefaultBaseClass, modelType);
58 | throw new TemplateException("Code language {0} is not supported.".FormatWith(context.Host.CodeLanguage));
59 | }
60 |
61 | public string ModelType { get; private set; }
62 |
63 | public override string ToString()
64 | {
65 | return "Model:" + ModelType;
66 | }
67 | public override bool Equals(object obj)
68 | {
69 | var other = obj as SetModelCodeGenerator;
70 | return other != null && string.Equals(ModelType, other.ModelType, StringComparison.Ordinal);
71 | }
72 | public override int GetHashCode()
73 | {
74 | return ModelType.GetHashCode();
75 | }
76 | }
77 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Core/Generator/VB/XiptonVBCodeLanguage.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System.Web.Razor;
9 | using System.Web.Razor.Parser;
10 |
11 | namespace Xipton.Razor.Core.Generator.VB
12 | {
13 | public class XiptonVBCodeLanguage : VBRazorCodeLanguage, IXiptonCodeLanguage
14 | {
15 | public override ParserBase CreateCodeParser()
16 | {
17 | return new XiptonVBCodeParser();
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Core/Generator/VB/XiptonVBCodeParser.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System.Web.Razor.Generator;
9 | using System.Web.Razor.Parser;
10 | using System.Web.Razor.Parser.SyntaxTree;
11 | using System.Web.Razor.Tokenizer.Symbols;
12 |
13 | namespace Xipton.Razor.Core.Generator.VB
14 | {
15 | ///
16 | /// This VB CodeParser is extended for being able to handle the @ModelType directive
17 | ///
18 | public class XiptonVBCodeParser : VBCodeParser
19 | {
20 |
21 | private static class Constants
22 | {
23 | public const string ModelKeyword = "ModelType";
24 | public const string ParseErrorInheritsKeywordMustBeFollowedByTypeName = "The 'ModelType' keyword must be followed by a type name on the same line.";
25 | }
26 | public XiptonVBCodeParser()
27 | {
28 | MapDirective(Constants.ModelKeyword, ModelStatement);
29 | }
30 |
31 | protected virtual bool ModelStatement()
32 | {
33 | Span.CodeGenerator = SpanCodeGenerator.Null;
34 | Context.CurrentBlock.Type = BlockType.Directive;
35 | AcceptAndMoveNext();
36 | var currentLocation = CurrentLocation;
37 | if (At(VBSymbolType.WhiteSpace))
38 | {
39 | Span.EditHandler.AcceptedCharacters = AcceptedCharacters.None;
40 | }
41 | AcceptWhile(VBSymbolType.WhiteSpace);
42 | Output(SpanKind.MetaCode);
43 | if (EndOfFile || At(VBSymbolType.WhiteSpace) || At(VBSymbolType.NewLine))
44 | {
45 | Context.OnError(currentLocation, Constants.ParseErrorInheritsKeywordMustBeFollowedByTypeName);
46 | }
47 | AcceptUntil(VBSymbolType.NewLine);
48 | if (!Context.DesignTimeMode)
49 | {
50 | Optional(VBSymbolType.NewLine);
51 | }
52 | string model = Span.GetContent();
53 | Span.CodeGenerator = new SetModelCodeGenerator(model);
54 | Output(SpanKind.Code);
55 | return false;
56 | }
57 |
58 | }
59 |
60 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Core/Generator/XiptonEngineHost.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Linq;
11 | using System.Web.Razor;
12 | using System.Web.Razor.Generator;
13 | using Xipton.Razor.Config;
14 |
15 | namespace Xipton.Razor.Core.Generator
16 | {
17 | ///
18 | /// The engine host is the part where the code rendering takes place.
19 | ///
20 | public class XiptonEngineHost : RazorEngineHost
21 | {
22 | #region Fields
23 | private readonly RazorConfig
24 | _config;
25 |
26 | private string
27 | _defaultBaseClass,
28 | _defaultNamespace;
29 |
30 | private GeneratedClassContext
31 | _generatedClassContext;
32 |
33 | private readonly ISet
34 | _namespaceImports;
35 | #endregion
36 |
37 | ///
38 | /// Initializes a new instance of the class.
39 | ///
40 | /// The config holds all settings that are needed to initialzie the host.
41 | public XiptonEngineHost(RazorConfig config)
42 | : base(config.Templates.Language)
43 | {
44 | if (config == null) throw new ArgumentNullException("config");
45 | _defaultNamespace = "Xipton.Razor.Generated";
46 | _config = config.AsReadonly();
47 | _defaultBaseClass = _config.Templates.NonGenericBaseTypeName;
48 | _namespaceImports = new HashSet();
49 | _config.Namespaces.ToList().ForEach(ns => _namespaceImports.Add(ns));
50 |
51 | // the GeneratedClassContext defines the methods that are generated to handle the template
52 | // control like writing the generated output and also handle other control operations like
53 | // defining sections inside the template
54 | _generatedClassContext = new GeneratedClassContext("Execute", "Write", "WriteLiteral", "WriteTo", "WriteLiteralTo", typeof(HelperResult).FullName, "DefineSection") {
55 | ResolveUrlMethodName = "ResolveUrl",
56 | };
57 |
58 | }
59 |
60 | public override string DefaultBaseClass
61 | {
62 | get { return _defaultBaseClass; }
63 | set { _defaultBaseClass = value; }
64 | }
65 |
66 | public override GeneratedClassContext GeneratedClassContext
67 | {
68 | get { return _generatedClassContext; }
69 | set { _generatedClassContext = value; }
70 | }
71 |
72 | public override ISet NamespaceImports
73 | {
74 | get { return _namespaceImports; }
75 | }
76 |
77 | public override string DefaultNamespace
78 | {
79 | get { return _defaultNamespace; }
80 | set{ _defaultNamespace = value; }
81 | }
82 |
83 | }
84 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Core/HelperResult.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 | using System;
8 | using System.Globalization;
9 | using System.IO;
10 |
11 | namespace Xipton.Razor.Core {
12 |
13 | public class HelperResult : ILiteralString {
14 | private readonly Action _action;
15 |
16 | public HelperResult(Action action) {
17 | if (action == null) throw new ArgumentNullException("action");
18 | _action = action;
19 | }
20 |
21 | public override string ToString() {
22 | using (var writer = new StringWriter(CultureInfo.InvariantCulture)) {
23 | _action(writer);
24 | return writer.ToString();
25 | }
26 | }
27 |
28 |
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Core/IContentProvider.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 | using System.Xml.Linq;
10 |
11 | namespace Xipton.Razor.Core
12 | {
13 | ///
14 | /// The contentent provider provides content by its virtual path.
15 | ///
16 | public interface IContentProvider
17 | {
18 | ///
19 | /// Occurs when content is modified. If the corresponding content provider provides content that
20 | /// cannot be modified, this event is never thrown by that instance, e.g., an embedded resource content provider.
21 | ///
22 | event EventHandler ContentModified;
23 | ///
24 | /// Maps the virtual path to the native resource name, e.g., a file system path name,
25 | /// an embedded resource name, a database key, etc... You could use such a native name
26 | /// as a cache key
27 | ///
28 | /// The virtual path.
29 | /// The reousrce name or null if no resource was found
30 | string TryGetResourceName(string virtualPath);
31 |
32 | ///
33 | /// Returns the content by its native resource name. It must return null
34 | /// if no content was found.
35 | ///
36 | /// Name of the resource.
37 | /// The content of null if no content was found
38 | string TryGetContent(string resourceName);
39 |
40 | ///
41 | /// Initializes this instance from the corresponding configuration node.
42 | ///
43 | /// The configuration element.
44 | ///
45 | IContentProvider InitFromConfig(XElement element);
46 | }
47 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Core/ITemplateController.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | namespace Xipton.Razor.Core
9 | {
10 |
11 | public interface ITemplateController : ITemplate
12 | {
13 | ITemplateController SetModel(object model);
14 | ITemplateController SetViewBag(object viewBag);
15 | ITemplateController ApplyLayout(ITemplateController layoutTemplate);
16 | ITemplateController SetVirtualPath(string virualPath);
17 | ITemplateController SetContext(RazorContext context);
18 | ITemplateController SetParent(ITemplateController parent);
19 | ITemplateController AddChild(ITemplateController child);
20 | ITemplateController Execute();
21 | ITemplateController TryApplyLayout();
22 | ITemplateController SetGeneratedSourceCode(string generatedSourceCode);
23 | string RenderSectionByChildRequest(string sectionName);
24 | }
25 |
26 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Core/TemplateBindingException.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 | using System.Runtime.Serialization;
10 |
11 | namespace Xipton.Razor.Core
12 | {
13 | // thrown if any runtime binding error (late binding error) occurs at any template
14 | [Serializable]
15 | public class TemplateBindingException : TemplateException
16 | {
17 | public TemplateBindingException()
18 | {
19 | }
20 |
21 | public TemplateBindingException(string message)
22 | : base(message)
23 | {
24 | }
25 |
26 | public TemplateBindingException(string message, Exception inner)
27 | : base(message, inner)
28 | {
29 | }
30 |
31 | protected TemplateBindingException(
32 | SerializationInfo info,
33 | StreamingContext context)
34 | : base(info, context)
35 | {
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Core/TemplateCompileException.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 | using System.Runtime.Serialization;
10 |
11 | namespace Xipton.Razor.Core
12 | {
13 | [Serializable]
14 | public class TemplateCompileException : TemplateException
15 | {
16 | public TemplateCompileException()
17 | {
18 | }
19 |
20 | public TemplateCompileException(string message) : base(message)
21 | {
22 | }
23 |
24 | public TemplateCompileException(string message, Exception inner) : base(message, inner)
25 | {
26 | }
27 |
28 | protected TemplateCompileException(
29 | SerializationInfo info,
30 | StreamingContext context) : base(info, context)
31 | {
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Core/TemplateException.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 | using System.Runtime.Serialization;
10 |
11 | namespace Xipton.Razor.Core
12 | {
13 | [Serializable]
14 | public class TemplateException : Exception
15 | {
16 |
17 | public TemplateException()
18 | {
19 | }
20 |
21 | public TemplateException(string message) : base(message)
22 | {
23 | }
24 |
25 | public TemplateException(string message, Exception inner) : base(message, inner)
26 | {
27 | }
28 |
29 | protected TemplateException(
30 | SerializationInfo info,
31 | StreamingContext context) : base(info, context)
32 | {
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Core/TemplateFactory.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 | using System.CodeDom;
10 | using System.CodeDom.Compiler;
11 | using System.Collections.Concurrent;
12 | using System.Collections.Generic;
13 | using System.IO;
14 | using System.Linq;
15 | using System.Reflection;
16 | using System.Text;
17 | using System.Web.Razor;
18 | using Xipton.Razor.Core.Generator;
19 | using Xipton.Razor.Extension;
20 |
21 | namespace Xipton.Razor.Core
22 | {
23 | ///
24 | /// The TemplateFactory provides template instances by their virtual path names.
25 | /// The corresponding template types are cached, the template instances are not cached
26 | /// The template factory needs a context to be injected at the constructor. The context is passed to each created template instance
27 | ///
28 | public class TemplateFactory : IDisposable {
29 |
30 | #region Types
31 | private class CacheBucket
32 | {
33 | public CacheBucket(Type generatedTemplateType){
34 | GeneratedTemplateType = generatedTemplateType;
35 | }
36 | public Type GeneratedTemplateType { get; private set; }
37 | public string GeneratedSourceCode { get; set; }
38 |
39 | public override bool Equals(object obj) {
40 | var other = obj as CacheBucket;
41 | return other != null && other.GeneratedTemplateType == GeneratedTemplateType;
42 | }
43 | public override int GetHashCode() {
44 | return GeneratedTemplateType == null ? 0 : GeneratedTemplateType.GetHashCode();
45 | }
46 | }
47 | #endregion
48 |
49 | #region Fields
50 | private const string
51 | _sourceFilenamePrefix = "template: ";
52 |
53 | private readonly ConcurrentDictionary
54 | _compiledTemplateTypeCache = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase);
55 |
56 | private readonly RazorTemplateEngine
57 | _razorEngine;
58 |
59 | private readonly RazorContext
60 | _razorContext;
61 | #endregion
62 |
63 | public TemplateFactory(RazorContext razorContext) {
64 | if (razorContext == null) throw new ArgumentNullException("razorContext");
65 | _razorContext = razorContext;
66 | _razorEngine = new RazorTemplateEngine(new XiptonEngineHost(razorContext.Config));
67 | ContentManager = new ContentManager(razorContext.Config);
68 | ContentManager.ContentProvider.ContentModified += OnContentModified;
69 | ContentManager.SharedContentModified += OnSharedContentModified;
70 | }
71 |
72 | #region Public
73 |
74 | public ContentManager ContentManager { get; private set; }
75 |
76 | public ITemplate CreateTemplateInstance(string requestedVirtualTemplateName, bool throwExceptionOnVirtualPathNotFound = true)
77 | {
78 | // all caching is done by the native resource names because any change notification is done with the native resource name as a parameter
79 | var resourceName = ContentManager.TryGetResourceName(requestedVirtualTemplateName);
80 | if (resourceName == null){
81 | if (throwExceptionOnVirtualPathNotFound)
82 | throw new TemplateException("Template '{0}' not found.".FormatWith(requestedVirtualTemplateName));
83 | return null;
84 | }
85 |
86 | var bucket = _compiledTemplateTypeCache.GetOrAdd(resourceName, key => CreateBucket(requestedVirtualTemplateName));
87 |
88 | // note that the types are cached, and not the template instances
89 | var template = bucket
90 | .GeneratedTemplateType
91 | .CreateInstance()
92 | .CastTo()
93 | .SetVirtualPath(ContentManager.TryGetVirtualPath(requestedVirtualTemplateName))
94 | .CastTo()
95 | .SetGeneratedSourceCode(bucket.GeneratedSourceCode)
96 | .SetContext(_razorContext);
97 |
98 | return template;
99 | }
100 |
101 | public void ClearTypeCache()
102 | {
103 | _compiledTemplateTypeCache.Clear();
104 | }
105 |
106 | #endregion
107 |
108 | #region Implementation of IDisposable
109 |
110 | public void Dispose() {
111 | Dispose(true);
112 | }
113 |
114 | private void Dispose(bool disposing) {
115 | if (!disposing) return;
116 | var provider = ContentManager;
117 | ContentManager = null;
118 | if (provider == null) return;
119 | provider.ContentProvider.ContentModified -= OnContentModified;
120 | provider.SharedContentModified -= OnSharedContentModified;
121 | provider.Dispose();
122 | }
123 |
124 | #endregion
125 |
126 | #region Private
127 |
128 | private void OnContentModified(object sender, ContentModifiedArgs e)
129 | {
130 | CacheBucket value;
131 | _compiledTemplateTypeCache.TryRemove(e.ModifiedResourceName, out value);
132 | }
133 |
134 | private void OnSharedContentModified(object sender, ContentModifiedArgs e)
135 | {
136 | // clear the whole cache is any shared content has been modified
137 | ClearTypeCache();
138 | }
139 |
140 | private CacheBucket CreateBucket(string reqestedPath) {
141 | var virtualPath = ContentManager.TryGetVirtualPath(reqestedPath);
142 | var resourceName = ContentManager.TryGetResourceName(virtualPath);
143 | var content = ContentManager.TryGetContent(virtualPath);
144 | string className, rootNamespace;
145 | GetClassName(virtualPath, out rootNamespace, out className);
146 | string generatedSource;
147 | var assembly = CreateAssembly(resourceName, @rootNamespace, className, content, out generatedSource);
148 | return new CacheBucket(assembly.GetType(rootNamespace + "." + className, true, false)){GeneratedSourceCode = generatedSource };
149 | }
150 |
151 | private Assembly CreateAssembly(string resourceName, string rootNamespace, string className, string content, out string generatedSource)
152 | {
153 | using (var codeProvider = CreateCodeProvider())
154 | {
155 | using (var stringReader = new StringReader(content)) {
156 | var generatorResult = _razorEngine.GenerateCode(
157 | stringReader,
158 | className,
159 | rootNamespace,
160 | "{0}{1}".FormatWith(_sourceFilenamePrefix, resourceName)
161 | );
162 | generatedSource = _razorContext.Config.Templates.IncludeGeneratedSourceCode ? GenerateSourceCode(generatorResult.GeneratedCode) : null;
163 |
164 | if (!CheckParseResults(resourceName, generatorResult, content))
165 | return null;
166 |
167 |
168 | var compilerParameter = new CompilerParameters(_razorContext.Config.References.ToArray()) { GenerateInMemory = true, CompilerOptions = "/optimize" };
169 |
170 | var compilerResults = codeProvider.CompileAssemblyFromDom(compilerParameter, generatorResult.GeneratedCode);
171 |
172 | return !CheckCompileResults(generatorResult, compilerResults, content, generatedSource) ? null : compilerResults.CompiledAssembly;
173 | }
174 | }
175 | }
176 |
177 | private void GetClassName(string virtualTemplatePath, out string @namespace, out string className)
178 | {
179 | virtualTemplatePath = new VirtualPathBuilder(_razorContext.Config.RootOperator.Path)
180 | .CombineWith(virtualTemplatePath)
181 | .Normalize()
182 | .WithRootOperator()
183 | .RemoveExtension()
184 | .ToString()
185 | .RemoveRoot();
186 | var sb = new StringBuilder();
187 | bool firstTokenChar = true;
188 | foreach(var ch in virtualTemplatePath)
189 | {
190 | if (ch >= '0' && ch <= '9'){
191 | if (firstTokenChar)
192 | sb.Append('_');
193 | sb.Append(ch);
194 | firstTokenChar = false;
195 | }
196 | else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_'){
197 | sb.Append(firstTokenChar ? char.ToUpper(ch) : ch);
198 | firstTokenChar = false;
199 | }
200 | else if (ch == '/'){
201 | sb.Append('.');
202 | firstTokenChar = true;
203 | }
204 |
205 | }
206 | className = sb.ToString();
207 | var index = className.LastIndexOf(".", StringComparison.Ordinal);
208 | if (index == -1)
209 | {
210 | @namespace = _razorEngine.Host.DefaultNamespace;
211 | }
212 | else
213 | {
214 | @namespace = className.Substring(0, index);
215 | className = className.Substring(index + 1);
216 | }
217 | }
218 |
219 | private CodeDomProvider CreateCodeProvider()
220 | {
221 | return _razorEngine
222 | .Host
223 | .CodeLanguage
224 | .CodeDomProviderType
225 | .CreateInstance()
226 | .CastTo();
227 | }
228 |
229 | private static bool CheckParseResults(string resourceName, GeneratorResults generatorResults, string templateContent)
230 | {
231 | if (!generatorResults.ParserErrors.Any())
232 | return true;
233 |
234 | var contentlines = templateContent
235 | .Split('\n')
236 | .Select(line => line.Trim())
237 | .ToList();
238 | string parseExceptionMessage;
239 |
240 | try
241 | {
242 | parseExceptionMessage = string.Join(
243 | Environment.NewLine,
244 | generatorResults
245 | .ParserErrors
246 | .Select(error => "parse error at template: {0}{1}line {2}: {3}{1}parse error: {4}".FormatWith(resourceName, Environment.NewLine, error.Location.LineIndex + 1, contentlines[error.Location.LineIndex], error.Message))
247 | .ToArray()
248 | );
249 | }
250 | catch
251 | {
252 | // on any error create a raw error message
253 | parseExceptionMessage = string.Join(
254 | Environment.NewLine,
255 | generatorResults
256 | .ParserErrors
257 | .Select(error => error.ToString())
258 | .ToArray());
259 | }
260 |
261 | throw new TemplateParseException(parseExceptionMessage);
262 | }
263 | private bool CheckCompileResults(GeneratorResults generatorResults, CompilerResults compilerResults, string templateContent, string generatedSource)
264 | {
265 | if (!compilerResults.Errors.HasErrors)
266 | return true;
267 |
268 | List sourceLines = null;
269 | Func> generatedSourceLines = () => sourceLines ?? (sourceLines = (generatedSource ?? GenerateSourceCode(generatorResults.GeneratedCode)).Split('\n').Select(line => line.Trim()).ToList());
270 |
271 | var contentlines = templateContent
272 | .Split('\n')
273 | .Select(line => line.Trim())
274 | .ToList();
275 |
276 | string compileExceptionMessage;
277 | try
278 | {
279 | compileExceptionMessage =
280 | string.Join(
281 | "{0}{0}".FormatWith(Environment.NewLine),
282 | compilerResults
283 | .Errors
284 | .OfType()
285 | .Where(error => !error.IsWarning)
286 | .Select(error => "compile error at {0}{1}line {2}: {3}{1}compile error: {4}: {5}".FormatWith(error.FileName, Environment.NewLine, error.Line, (error.FileName ?? "").StartsWith(_sourceFilenamePrefix) ? contentlines[error.Line - 1] : generatedSourceLines()[error.Line - 1], error.ErrorNumber, error.ErrorText))
287 | .ToArray()
288 | );
289 | }
290 | catch
291 | {
292 | // on any error create a raw error message
293 | compileExceptionMessage = string.Join(
294 | "{0}{0}".FormatWith(Environment.NewLine),
295 | compilerResults
296 | .Errors
297 | .OfType()
298 | .Where(error => !error.IsWarning)
299 | .Select(error => error.ToString())
300 | .ToArray());
301 | }
302 |
303 | throw new TemplateCompileException(compileExceptionMessage);
304 | }
305 |
306 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times", Justification = "StringWriter can be disposed more than once.")]
307 | private string GenerateSourceCode(CodeCompileUnit compileunit)
308 | {
309 | using (var sw = new StringWriter())
310 | {
311 | using (var tw = new IndentedTextWriter(sw, " "))
312 | CreateCodeProvider().GenerateCodeFromCompileUnit(compileunit, tw, new CodeGeneratorOptions());
313 | return sw.ToString();
314 | }
315 | }
316 |
317 | #endregion
318 |
319 | }
320 | }
321 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Core/TemplateParseException.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 | using System.Runtime.Serialization;
10 |
11 | namespace Xipton.Razor.Core
12 | {
13 | [Serializable]
14 | public class TemplateParseException : TemplateException
15 | {
16 | public TemplateParseException()
17 | {
18 | }
19 |
20 | public TemplateParseException(string message)
21 | : base(message)
22 | {
23 | }
24 |
25 | public TemplateParseException(string message, Exception inner)
26 | : base(message, inner)
27 | {
28 | }
29 |
30 | protected TemplateParseException(
31 | SerializationInfo info,
32 | StreamingContext context)
33 | : base(info, context)
34 | {
35 | }
36 | }
37 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Core/TemplateTreeException.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 | using System.Runtime.Serialization;
10 |
11 | namespace Xipton.Razor.Core
12 | {
13 | // thrown if there are problems detected with the template tree (parent or childs)
14 | [Serializable]
15 | public class TemplateTreeException : TemplateException
16 | {
17 | public TemplateTreeException()
18 | {
19 | }
20 |
21 | public TemplateTreeException(string message)
22 | : base(message)
23 | {
24 | }
25 |
26 | public TemplateTreeException(string message, Exception inner)
27 | : base(message, inner)
28 | {
29 | }
30 |
31 | protected TemplateTreeException(
32 | SerializationInfo info,
33 | StreamingContext context)
34 | : base(info, context)
35 | {
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Extension/AppDomainExtension.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 | using System.Collections.Concurrent;
10 | using System.IO;
11 | using System.Linq;
12 | using System.Reflection;
13 | using System.Web.Razor;
14 |
15 | namespace Xipton.Razor.Extension {
16 | public static class AppDomainExtension {
17 |
18 | private static readonly ConcurrentDictionary
19 | _binAssembliesLoadedBefore = new ConcurrentDictionary();
20 |
21 | ///
22 | /// Ensures that the required xipton assemblies are loaded in the excution context.
23 | ///
24 | public static AppDomain EnsureXiptonAssembliesLoaded(this AppDomain domain) {
25 | #pragma warning disable 168
26 | var t = typeof(ParserResults);
27 | #pragma warning restore 168
28 | return domain;
29 | }
30 |
31 | ///
32 | /// Ensures that all assemblies in the bin folder have been loaded into the excution context.
33 | ///
34 | public static AppDomain EnsureBinAssembliesLoaded(this AppDomain domain) {
35 |
36 | if (_binAssembliesLoadedBefore.ContainsKey(domain.FriendlyName))
37 | return domain;
38 |
39 | var binFolder = !string.IsNullOrEmpty(domain.RelativeSearchPath)
40 | ? Path.Combine(domain.BaseDirectory, domain.RelativeSearchPath)
41 | : domain.BaseDirectory;
42 |
43 | Directory.GetFiles(binFolder, "*.dll")
44 | .Union(Directory.GetFiles(binFolder, "*.exe"))
45 | .ToList()
46 | .ForEach(domain.EnsureAssemblyIsLoaded);
47 |
48 | _binAssembliesLoadedBefore[domain.FriendlyName] = true;
49 |
50 | return domain;
51 | }
52 |
53 | public static Assembly GetOrLoadAssembly(this AppDomain domain, string assemblyFileNameOrAssemblyDisplayName) {
54 | var assemblyName = assemblyFileNameOrAssemblyDisplayName.IsFileName()
55 | ? AssemblyName.GetAssemblyName(assemblyFileNameOrAssemblyDisplayName)
56 | : new AssemblyName(assemblyFileNameOrAssemblyDisplayName);
57 | return domain
58 | .GetAssemblies()
59 | .FirstOrDefault(a => ReferenceMatchesDefinitionEx(assemblyName, a.GetName())) ?? domain.Load(assemblyName);
60 | }
61 |
62 | private static void EnsureAssemblyIsLoaded(this AppDomain domain, string assemblyFileName) {
63 | try{
64 | var assemblyName = AssemblyName.GetAssemblyName(assemblyFileName);
65 | if (!domain.GetAssemblies().Any(a => ReferenceMatchesDefinitionEx(assemblyName, a.GetName()))){
66 | domain.Load(assemblyName);
67 | }
68 | }
69 | catch (BadImageFormatException){
70 | // thrown by GetAssemblyName
71 | // ignore this assembly since it is an unmanaged assembly
72 | }
73 | }
74 |
75 | private static bool ReferenceMatchesDefinitionEx(AssemblyName reference, AssemblyName definition)
76 | {
77 | #if __MonoCS__
78 | return string.Equals(reference.ToString(), definition.ToString(), StringComparison.OrdinalIgnoreCase);
79 | #else
80 | return AssemblyName.ReferenceMatchesDefinition(reference, definition);
81 | #endif
82 | }
83 |
84 |
85 |
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Extension/AssemblyExtension.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 | using System.IO;
10 | using System.Reflection;
11 |
12 | namespace Xipton.Razor.Extension
13 | {
14 | public static class AssemblyExtension
15 | {
16 | public static string GetFileName(this Assembly assembly)
17 | {
18 |
19 | #if __MonoCS__
20 | return assembly == null
21 | ? null
22 | : new DirectoryInfo(IsNotWindows ? assembly.CodeBase.Replace("file:///", "/") : assembly.CodeBase.Replace("file:///", string.Empty)).FullName;
23 | #else
24 | return assembly == null
25 | ? null
26 | : new DirectoryInfo(assembly.CodeBase.Replace("file:///", string.Empty)).FullName;
27 | #endif
28 |
29 | }
30 |
31 | public static bool IsNotWindows
32 | {
33 | get
34 | {
35 | var p = (int)Environment.OSVersion.Platform;
36 | return (p == 4) || (p == 6) || (p == 128);
37 | }
38 | }
39 |
40 | //http://msdn.microsoft.com/en-us/library/ms173100.aspx
41 | public static bool IsManagedAssembly(this string self) {
42 |
43 | if (self == null || !File.Exists(self)) {
44 | return false;
45 | }
46 |
47 | try{
48 | AssemblyName.GetAssemblyName(self);
49 | return true;
50 | }
51 | catch (BadImageFormatException){
52 | return false;
53 | }
54 | catch (FileLoadException){
55 | return true;
56 | }
57 | catch{
58 | return false;
59 | }
60 |
61 | }
62 |
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Extension/ObjectExtension.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 |
10 | namespace Xipton.Razor.Extension
11 | {
12 | public static class ObjectExtension
13 | {
14 | public static T CastTo(this object target)
15 | {
16 | return target == null ? default(T) : (T) target;
17 | }
18 |
19 | public static bool TryDispose(this object target)
20 | {
21 | var disposable = target as IDisposable;
22 | if (disposable != null)
23 | {
24 | disposable.Dispose();
25 | return true;
26 | }
27 | return false;
28 | }
29 |
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Extension/StringExtension.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 | using System.IO;
10 |
11 | namespace Xipton.Razor.Extension
12 | {
13 | public static class StringExtension
14 | {
15 |
16 | public static string FormatWith(this string format, params object[] args)
17 | {
18 | return format == null ? null : string.Format(format, args);
19 | }
20 |
21 | public static bool NullOrEmpty(this string value)
22 | {
23 | return string.IsNullOrEmpty(value);
24 | }
25 |
26 | public static string EmptyAsNull(this string value) {
27 | return string.IsNullOrEmpty(value) ? null : value;
28 | }
29 |
30 | public static bool HasVirtualRootOperator(this string path)
31 | {
32 | return path != null && path.StartsWith("~");
33 | }
34 |
35 | public static string RemoveRoot(this string path)
36 | {
37 | if (path.NullOrEmpty()) return path;
38 | if (path[0] == '~') path = path.Substring(1);
39 | return path.TrimStart('\\').TrimStart('/');
40 | }
41 |
42 | public static bool IsAbsoluteVirtualPath(string path)
43 | {
44 | return path != null && (path.Contains(":") || path.StartsWith("/") || path.StartsWith("\\"));
45 | }
46 |
47 | public static string MakeAbsoluteDirectoryPath(this string path){
48 | var baseDir = Path.GetDirectoryName(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
49 | if (baseDir == null)
50 | return path;
51 | return Path.Combine(baseDir, path ?? ".");
52 | }
53 |
54 | public static string HtmlEncode(this string value)
55 | {
56 | return value == null ? null : System.Net.WebUtility.HtmlEncode(value);
57 | }
58 |
59 | internal static bool IsFileName(this string path) {
60 | return path != null && File.Exists(path);
61 | }
62 | internal static bool IsXmlContent(this string content) {
63 | return content != null && content.TrimStart().StartsWith("<");
64 | }
65 | internal static bool IsUrl(this string value) {
66 | return value != null && (value.HasVirtualRootOperator() || value.StartsWith("/"));
67 | }
68 |
69 | }
70 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Extension/TemplateExtension.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 |
10 | namespace Xipton.Razor.Extension
11 | {
12 | //pre compile view extension
13 | public static class RazorMachineExtension
14 | {
15 | public static void EnsureViewCompiled(this RazorMachine self, string path, bool throwException = true)
16 | {
17 | if (self == null) throw new ArgumentNullException("self");
18 | self.Context.TemplateFactory.CreateTemplateInstance(path, throwException);
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Extension/TypeExtension.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 |
10 | namespace Xipton.Razor.Extension
11 | {
12 | public static class TypeExtension
13 | {
14 | public static object CreateInstance(this Type type)
15 | {
16 | return type == null ? null : Activator.CreateInstance(type, true);
17 | }
18 |
19 | public static T CreateInstance(this Type type) {
20 | return type == null ? default(T) : (T)Activator.CreateInstance(type, true);
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor/ILiteralString.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 | namespace Xipton.Razor
8 | {
9 | public interface ILiteralString{}
10 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor/IRazorMachine.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Xipton.Razor
4 | {
5 | public interface IRazorMachine
6 | {
7 | ///
8 | /// Executes the template by its virtual path and returns the resulting executed template instance.
9 | ///
10 | /// The requested virtual path for the template.
11 | /// The optional model.
12 | /// The optional viewbag.
13 | /// if set true then any layout setting is ignored
14 | ///
15 | /// Optional. If set to true an exception is thrown if the requested path could not be resolved.
16 | /// If set to false then null is returned if the requested path could not be resolved.
17 | ///
18 | /// An executed template instance. The corresponding rendered result can be found at
19 | ITemplate ExecuteUrl(string templateVirtualPath, object model = null, object viewbag = null, bool skipLayout = false, bool throwExceptionOnVirtualPathNotFound = true);
20 |
21 | ///
22 | /// Renders the specified template content's result with the passed model instance and returns the template's rendered result.
23 | /// A corresponding virtual path is generated internally for being able to keep the compiled template type cached.
24 | ///
25 | /// Content of the template.
26 | /// The model
27 | /// The optional viewbag
28 | /// if set to true then any layout setting (probably at _ViewStart) is ignored.
29 | ///
30 | /// The rendered string
31 | ///
32 | ITemplate ExecuteContent(string templateContent, object model = null, object viewbag = null, bool skipLayout = false);
33 |
34 | ///
35 | /// Hybrid convenience executer. It decides whether to execute content or an url.
36 | ///
37 | /// Content of the template URL or.
38 | /// The model.
39 | /// The viewbag.
40 | /// if set to true [skip layout].
41 | /// if set to true [throw exception on virtual path not found].
42 | ///
43 | ITemplate Execute(string templateVirtualPathOrContent, object model = null, object viewbag = null, bool skipLayout = false, bool throwExceptionOnVirtualPathNotFound = true);
44 |
45 | RazorContext Context { get; }
46 | RazorMachine RegisterTemplate(string virtualPath, string content);
47 | RazorMachine RemoveTemplate(string virtualPath);
48 | IDictionary GetRegisteredInMemoryTemplates();
49 | RazorMachine ClearTypeCache();
50 | }
51 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor/ITemplate.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 | using System.Collections.Generic;
10 | using Xipton.Razor.Core;
11 |
12 | namespace Xipton.Razor
13 | {
14 | ///
15 | /// All templates need to implement this interface. It is implementated by .
16 | ///
17 | ///
18 | /// for interchangeability reasons some operations are (about) the same as MVC view operations.
19 | ///
20 | public interface ITemplate {
21 |
22 | #region MVC complient
23 | string Layout { get; set; }
24 | dynamic Model { get; }
25 | dynamic ViewBag { get; }
26 | LiteralString RenderBody();
27 |
28 | // you may skip the layout using the parameter skipLayoutwhich can be handy
29 | // when rendering template partials (controls)
30 | LiteralString RenderPage(string name, object model = null, bool skipLayout = false);
31 |
32 | LiteralString RenderSection(string sectionName, bool required = false);
33 | bool IsSectionDefined(string sectionName);
34 | #endregion
35 |
36 | // If set true then the Write method HTML encode the output.
37 | // The default setting can be configured.
38 | bool HtmlEncode { get; set; }
39 |
40 | // If generated source code must be included (needs to be configured)
41 | // then that source code can be accessed by this property
42 | // for debug purposes
43 | string GeneratedSourceCode { get; }
44 |
45 | // If this template is rendered by another template
46 | // (I am a layout or control) then that other template is
47 | // registered as the Parent and can be accessed during execution time
48 | ITemplate Parent { get; }
49 |
50 | // Any layout and all controls are registered as childs
51 | // The child list should not be accessed during
52 | // template execution, but only after complete execution.
53 | IList Childs { get; }
54 |
55 | // Returns the Root parent, or myself (this) if no Parent exists.
56 | ITemplate RootOrSelf { get; }
57 |
58 | // PathBuilder contains the virtual path as a starting point
59 | VirtualPathBuilder VirtualLocation { get; }
60 |
61 | // The actual virtual path that resolved this template
62 | string VirtualPath { get; }
63 |
64 | // Context gives access to the template factory and to the razor configuration
65 | RazorContext RazorContext { get; }
66 |
67 | // The rendered result
68 | String Result { get; }
69 |
70 | // Writes encoded output only if HtmlEncode is true
71 | void Write(object value);
72 |
73 | // Writes a literal string, never encoded
74 | void WriteLiteral(object value);
75 |
76 | // Ensures the value to be written as a raw string.
77 | // You can invoke it like: @Raw("a & b")
78 | LiteralString Raw(string value);
79 |
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor/ITemplate`1.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | namespace Xipton.Razor
9 | {
10 | ///
11 | /// This interface redefines the Model property making it typed
12 | ///
13 | /// The type of the model.
14 | public interface ITemplate : ITemplate
15 | {
16 | new TModel Model { get; }
17 | }
18 | }
--------------------------------------------------------------------------------
/Source/Xipton.Razor/LiteralString.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 |
10 | namespace Xipton.Razor {
11 | ///
12 | /// a LiteralString represents a string that should not be encoded (again)
13 | ///
14 | public class LiteralString : ILiteralString {
15 |
16 | private readonly string
17 | _literalString;
18 |
19 | public LiteralString(string literalString){
20 | _literalString = literalString;
21 | }
22 |
23 | public override bool Equals(object obj) {
24 | var other = obj as LiteralString;
25 | return Equals(_literalString, other != null ? other._literalString : obj);
26 | }
27 |
28 | public override int GetHashCode() {
29 | return _literalString != null ? _literalString.GetHashCode() : 0;
30 | }
31 |
32 | public static implicit operator String(LiteralString s){
33 | return s == null ? null : s._literalString;
34 | }
35 | public static implicit operator LiteralString(string s) {
36 | return new LiteralString(s);
37 | }
38 |
39 | public static bool operator ==(LiteralString s1, string s){
40 | return Equals(s1, null) ? Equals(s, null) : Equals(s1._literalString, s);
41 | }
42 | public static bool operator !=(LiteralString s1, string s){
43 | return !(s1 == s);
44 | }
45 |
46 | public override string ToString() {
47 | // should never return null
48 | return _literalString ?? string.Empty;
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | // General Information about an assembly is controlled through the following
5 | // set of attributes. Change these attribute values to modify the information
6 | // associated with an assembly.
7 | //[assembly:InternalsVisibleTo("Xipton.Razor.UnitTest")]
8 | [assembly: AssemblyTitle("Xipton.Razor")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Xipton")]
12 | [assembly: AssemblyProduct("Xipton.Razor")]
13 | [assembly: AssemblyCopyright("Copyright © 2013")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("3169c7ca-13f9-44a6-a5cd-08a83224af47")]
24 |
25 | [assembly: AssemblyVersion("3.1.0.0")]
26 | [assembly: AssemblyFileVersion("3.1.0.0")]
27 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor/RazorContext.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 | using Xipton.Razor.Config;
10 | using Xipton.Razor.Core;
11 | using Xipton.Razor.Extension;
12 |
13 | namespace Xipton.Razor
14 | {
15 | ///
16 | /// The RazorContext holds the template factory (with its type cache) and the configurtation.
17 | ///
18 | public class RazorContext : IDisposable
19 | {
20 | ///
21 | /// Initializes a new instance of the class.
22 | ///
23 | public RazorContext(RazorConfig config = null)
24 | {
25 | Config = (config ?? new RazorConfig().Initializer.TryInitializeFromConfig().CastTo()).AsReadonly();
26 | TemplateFactory = new TemplateFactory(this);
27 | }
28 |
29 | public RazorConfig Config { get; private set; }
30 | ///
31 | /// Gets the template factory. The template factory instantiates the template instances by a virtual template name.
32 | /// Internally it handles caching of the generated template types.
33 | ///
34 | public TemplateFactory TemplateFactory { get; private set; }
35 |
36 | #region Implementation of IDisposable
37 |
38 | public void Dispose()
39 | {
40 | Dispose(true);
41 | }
42 |
43 | protected virtual void Dispose(bool disposing)
44 | {
45 | if (!disposing) return;
46 | var target = TemplateFactory;
47 | TemplateFactory = null;
48 | if (target != null)
49 | {
50 | target.Dispose();
51 | }
52 | }
53 |
54 | #endregion
55 |
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor/RazorMachine.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | using System;
9 | using System.Collections.Concurrent;
10 | using System.Collections.Generic;
11 | using System.Web.Razor;
12 | using Xipton.Razor.Config;
13 | using Xipton.Razor.Core;
14 | using Xipton.Razor.Core.ContentProvider;
15 | using Xipton.Razor.Extension;
16 |
17 | namespace Xipton.Razor
18 | {
19 | ///
20 | /// The main razor template executer. Use a singleton instance because each instance creates its own type cache (at the template factory).
21 | ///
22 | public class RazorMachine : IDisposable, IRazorMachine
23 | {
24 |
25 | protected internal const string ContentGeneratedUrlPrefix = "~/_MemoryContent/_{0}";
26 |
27 | private readonly ConcurrentDictionary
28 | _templateContentToGeneratedVirtualPathMap = new ConcurrentDictionary();
29 |
30 | private readonly object _syncroot = new object();
31 |
32 | #region Constructors
33 | public RazorMachine(){
34 | Context = new RazorContext(new RazorConfig().Initializer.TryInitializeFromConfig().AsReadOnly());
35 | }
36 | public RazorMachine(RazorConfig config){
37 | Context = new RazorContext(config ?? new RazorConfig().Initializer.TryInitializeFromConfig().AsReadOnly());
38 | }
39 | public RazorMachine(string xmlContentOrFileName){
40 | if (xmlContentOrFileName == null)
41 | // default initialization (from app.config or else default settings)
42 | Context = new RazorContext(new RazorConfig().Initializer.TryInitializeFromConfig().AsReadOnly());
43 | else if (xmlContentOrFileName.IsFileName())
44 | // initialization by xml configuration file
45 | Context = new RazorContext(new RazorConfig().Initializer.InitializeByXmlFileName(xmlContentOrFileName).AsReadOnly());
46 | else if (xmlContentOrFileName.IsXmlContent())
47 | // initialization by literal xml configuration string
48 | Context = new RazorContext(new RazorConfig().Initializer.InitializeByXmlContent(xmlContentOrFileName).AsReadOnly());
49 | else
50 | throw new ArgumentException("Argument must be either an existing file name or literal xml content", "xmlContentOrFileName");
51 | }
52 |
53 | public RazorMachine(
54 | Type baseType = null,
55 | string rootOperatorPath = null,
56 | RazorCodeLanguage language = null,
57 | string defaultExtension = null,
58 | string autoIncludeNameWithoutExtension = null,
59 | string sharedLocation = null,
60 | bool? includeGeneratedSourceCode = null,
61 | bool? htmlEncode = null,
62 | IEnumerable references = null,
63 | IEnumerable namespaces = null,
64 | IEnumerable> contentProviders = null,
65 | bool replaceReferences = false,
66 | bool replaceNamespaces = false,
67 | bool replaceContentProviders = false
68 | )
69 | {
70 | Context = new RazorContext(new RazorConfig()
71 | .Initializer
72 | .TryInitializeFromConfig()
73 | .InitializeByValues(
74 | baseType,
75 | rootOperatorPath,
76 | language,
77 | defaultExtension,
78 | autoIncludeNameWithoutExtension,
79 | sharedLocation,
80 | includeGeneratedSourceCode,
81 | htmlEncode,
82 | references,
83 | namespaces,
84 | contentProviders,
85 | replaceReferences,
86 | replaceNamespaces,
87 | replaceContentProviders
88 | )
89 | .AsReadOnly()
90 | );
91 | }
92 |
93 | #endregion
94 |
95 | ///
96 | /// Executes the template by its virtual path and returns the resulting executed template instance.
97 | ///
98 | /// The requested virtual path for the template.
99 | /// The optional model.
100 | /// The optional viewbag.
101 | /// if set true then any layout setting is ignored
102 | ///
103 | /// Optional. If set to true an exception is thrown if the requested path could not be resolved.
104 | /// If set to false then null is returned if the requested path could not be resolved.
105 | ///
106 | /// An executed template instance. The corresponding rendered result can be found at
107 | public virtual ITemplate ExecuteUrl(string templateVirtualPath, object model = null, object viewbag = null, bool skipLayout = false, bool throwExceptionOnVirtualPathNotFound = true)
108 | {
109 | if (templateVirtualPath == null) throw new ArgumentNullException("templateVirtualPath");
110 |
111 | var instance = Context
112 | .TemplateFactory
113 | .CreateTemplateInstance(templateVirtualPath, throwExceptionOnVirtualPathNotFound);
114 |
115 | if (instance == null) return null;
116 |
117 | var template = instance
118 | .CastTo()
119 | .SetModel(model)
120 | .SetViewBag(viewbag)
121 | .Execute();
122 |
123 | if (!skipLayout)
124 | template.TryApplyLayout();
125 |
126 | return template;
127 | }
128 |
129 | ///
130 | /// Renders the specified template content's result with the passed model instance and returns the template's rendered result.
131 | /// A corresponding virtual path is generated internally for being able to keep the compiled template type cached.
132 | ///
133 | /// Content of the template.
134 | /// The model
135 | /// The optional viewbag
136 | /// if set to true then any layout setting (probably at _ViewStart) is ignored.
137 | ///
138 | /// The rendered string
139 | ///
140 | public virtual ITemplate ExecuteContent(string templateContent, object model = null, object viewbag = null, bool skipLayout = false) {
141 | if (templateContent == null) return null;
142 | var generatedVirtualPath = _templateContentToGeneratedVirtualPathMap.GetOrAdd(templateContent, k =>
143 | {
144 | var path = ContentGeneratedUrlPrefix.FormatWith(Guid.NewGuid().ToString("N"));
145 | RegisterTemplate(path, templateContent);
146 | return path;
147 | }
148 | );
149 | return ExecuteUrl(generatedVirtualPath, model, viewbag, skipLayout);
150 | }
151 |
152 | ///
153 | /// Hybrid convenience executer. It decides whether to execute content or an url.
154 | ///
155 | /// Content of the template URL or.
156 | /// The model.
157 | /// The viewbag.
158 | /// if set to true [skip layout].
159 | /// if set to true [throw exception on virtual path not found].
160 | ///
161 | public virtual ITemplate Execute(string templateVirtualPathOrContent, object model = null, object viewbag = null, bool skipLayout = false, bool throwExceptionOnVirtualPathNotFound = true){
162 | if (templateVirtualPathOrContent == null) throw new ArgumentNullException("templateVirtualPathOrContent");
163 | return templateVirtualPathOrContent.IsUrl()
164 | ? ExecuteUrl(templateVirtualPathOrContent, model, viewbag, skipLayout, throwExceptionOnVirtualPathNotFound)
165 | : ExecuteContent(templateVirtualPathOrContent, model, viewbag, skipLayout);
166 | }
167 |
168 | public RazorContext Context { get; private set; }
169 |
170 | public RazorMachine RegisterTemplate(string virtualPath, string content)
171 | {
172 | MemoryContentProvider.RegisterTemplate(NormalizeVirtualPath(virtualPath), content);
173 | return this;
174 | }
175 | public RazorMachine RemoveTemplate(string virtualPath) {
176 | MemoryContentProvider.RegisterTemplate(NormalizeVirtualPath(virtualPath),null);
177 | return this;
178 | }
179 | public IDictionary GetRegisteredInMemoryTemplates() {
180 | return MemoryContentProvider.GetRegisteredTemplates();
181 | }
182 |
183 | public RazorMachine ClearTypeCache(){
184 | Context.TemplateFactory.ClearTypeCache();
185 | return this;
186 | }
187 |
188 | protected MemoryContentProvider MemoryContentProvider {
189 | get
190 | {
191 | var provider = Context.TemplateFactory.ContentManager.TryGetContentProvider();
192 | if (provider != null) return provider;
193 | lock (_syncroot)
194 | {
195 | provider = Context.TemplateFactory.ContentManager.TryGetContentProvider();
196 | if (provider == null)
197 | Context.TemplateFactory.ContentManager.AddContentProvider(provider = new MemoryContentProvider());
198 | return provider;
199 | }
200 | }
201 | }
202 |
203 | protected string NormalizeVirtualPath(string virtualPath) {
204 | if (virtualPath.NullOrEmpty()) throw new ArgumentNullException("virtualPath");
205 | virtualPath = new VirtualPathBuilder(Context.Config.RootOperator.Path)
206 | .CombineWith(virtualPath)
207 | .WithRootOperator()
208 | .AddOrKeepExtension(Context.Config.Templates.DefaultExtension);
209 | return virtualPath;
210 | }
211 |
212 |
213 | #region Implementation of IDisposable
214 |
215 | public void Dispose()
216 | {
217 | Dispose(true);
218 | }
219 |
220 | protected virtual void Dispose(bool disposing)
221 | {
222 | if (!disposing) return;
223 | var context = Context;
224 | Context = null;
225 | if (context != null)
226 | context.Dispose();
227 | }
228 |
229 | #endregion
230 |
231 | }
232 | }
233 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor/TemplateBase`1.cs:
--------------------------------------------------------------------------------
1 | #region Microsoft Public License
2 | /* This code is part of Xipton.Razor v3.0
3 | * (c) Jaap Lamfers, 2013 - jaap.lamfers@xipton.net
4 | * Licensed under the Microsoft Public License (MS-PL) http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
5 | */
6 | #endregion
7 |
8 | namespace Xipton.Razor
9 | {
10 | ///
11 | /// Redefines the Model property, making it typed
12 | ///
13 | /// The type of the model.
14 | public abstract class TemplateBase : TemplateBase, ITemplate
15 | {
16 | ///
17 | /// Gets the model or the Parent's model (recursively) if the current model is null.
18 | /// If no model exists a new model is instantiated at RootOrSelf.
19 | ///
20 | public new TModel Model{
21 | get{return GetOrCreateModel();}
22 | }
23 |
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Xipton.Razor.Overview.cd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | Config\RazorConfig.cs
20 |
21 |
22 |
23 |
24 | Config\RazorConfig.cs
25 |
26 |
27 |
28 |
29 | Config\RazorConfig.cs
30 |
31 |
32 |
33 |
34 | AAAAAAEAQEgAAQAAiAEBAAAAAABQAAAAAQAAAAAiAAA=
35 | Config\RazorConfig.cs
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | Core\TemplateFactory.cs
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | CAABAAAAACAAAAAAAAAAiEAAgAAAIAhQAAAAAAMIAIA=
74 | Core\TemplateFactory.cs
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 | AAASQEAAEKAYGAAAQAAQSwACGAAAAAAAIgAIBgAAEIA=
112 | Core\ContentManager.cs
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 | BAAAQEAAECAACAAAAAAACQAAAAAAAgAAIAAKAAAAAIA=
135 | Core\ContentProvider\CompositeContentProvider.cs
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 | BAAAAAAAAAAAAAAAAAAACAAAAAACAAAAAAAqAAABAAA=
146 | Core\ContentProvider\EmbeddedResourceContentProvider.cs
147 |
148 |
149 |
150 |
151 |
152 |
153 | BAAAAAAAAWAAAAAAAAAACAAAAQAIAAAAAAAKAAAAAEQ=
154 | Core\ContentProvider\FileContentProvider.cs
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 | BAAAAAAAAAAAAQABAAAACAAAAAAAAAAAAAAKAAAAAAA=
169 | Core\ContentProvider\MemoryContentProvider.cs
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 | AAAAAAAAAiAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAA=
184 | RazorContext.cs
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 | BAAAAiAAAiAAAQQiAAAAAAAAAAAAAAAAAAAAAAEAAAA=
203 | RazorMachine.cs
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 | EAAEEAKRBAIBCswEEgRgSAQAYASABEgJQIwAQAFBgAU=
214 | TemplateBase.cs
215 |
216 |
217 |
218 |
219 |
220 |
221 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAA=
222 | TemplateBase`1.cs
223 |
224 |
225 |
226 |
227 |
228 |
229 | BAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAKAAAAAAA=
230 | Core\IContentProvider.cs
231 |
232 |
233 |
234 |
235 |
236 | AAAAAgEACAIAEAQCAAAAAAAAAAAAAAAAAkAAEABAAAA=
237 | Core\ITemplateInternal.cs
238 |
239 |
240 |
241 |
242 |
243 | AAAAAAABBAABCoQAEAAAQAQAAASAAEAIAAgAQAEAAAU=
244 | ITemplate.cs
245 |
246 |
247 |
248 |
249 |
250 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAA=
251 | ITemplate`1.cs
252 |
253 |
254 |
255 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor/Xipton.Razor.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 8.0.30703
7 | 2.0
8 | {3A7A2F2F-0B57-47F9-8E1A-D34ECB961831}
9 | Library
10 | Properties
11 | Xipton.Razor
12 | Xipton.Razor
13 | v4.5
14 | 512
15 |
16 |
17 |
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 | false
26 |
27 |
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 | false
35 |
36 |
37 | false
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | False
49 | ..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 | Code
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 | Always
111 | Designer
112 |
113 |
114 |
115 | Designer
116 |
117 |
118 |
119 |
120 |
121 |
128 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor/legacy/web.config:
--------------------------------------------------------------------------------
1 |
2 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/Source/Xipton.Razor/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------