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
45
46
47
48
49
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
|
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Security;
using System.Web.Compilation;
using System.Web.Razor;
using System.Web.Razor.Generator;
using System.Web.Razor.Parser.SyntaxTree;
namespace System.Web.WebPages.Razor
{
[BuildProviderAppliesTo(BuildProviderAppliesTo.Web | BuildProviderAppliesTo.Code)]
public class RazorBuildProvider : BuildProvider
{
private static bool? _isFullTrust;
private CodeCompileUnit _generatedCode = null;
private WebPageRazorHost _host = null;
private IList _virtualPathDependencies;
private IAssemblyBuilder _assemblyBuilder;
public static event EventHandler<CodeGenerationCompleteEventArgs> CodeGenerationCompleted;
internal event EventHandler<CodeGenerationCompleteEventArgs> CodeGenerationCompletedInternal
{
add { _codeGenerationCompletedInternal += value; }
remove { _codeGenerationCompletedInternal -= value; }
}
public static event EventHandler CodeGenerationStarted;
/// <summary>
/// For unit testing.
/// </summary>
internal event EventHandler CodeGenerationStartedInternal
{
add { _codeGenerationStartedInternal += value; }
remove { _codeGenerationStartedInternal -= value; }
}
public static event EventHandler<CompilingPathEventArgs> CompilingPath;
/// <summary>
/// For unit testing
/// </summary>
private event EventHandler<CodeGenerationCompleteEventArgs> _codeGenerationCompletedInternal;
private event EventHandler _codeGenerationStartedInternal;
internal WebPageRazorHost Host
{
get
{
if (_host == null)
{
_host = CreateHost();
}
return _host;
}
set { _host = value; }
}
// Returns the base dependencies and any dependencies added via AddVirtualPathDependencies
public override ICollection VirtualPathDependencies
{
get
{
if (_virtualPathDependencies != null)
{
// Return a readonly wrapper so as to prevent users from modifying the collection directly.
return ArrayList.ReadOnly(_virtualPathDependencies);
}
else
{
return base.VirtualPathDependencies;
}
}
}
public new string VirtualPath
{
get { return base.VirtualPath; }
}
public AssemblyBuilder AssemblyBuilder
{
get
{
var wrapper = _assemblyBuilder as AssemblyBuilderWrapper;
if (wrapper != null)
{
return wrapper.InnerBuilder;
}
else
{
return null;
}
}
}
// For unit testing
internal IAssemblyBuilder AssemblyBuilderInternal
{
get { return _assemblyBuilder; }
}
internal CodeCompileUnit GeneratedCode
{
get
{
EnsureGeneratedCode();
return _generatedCode;
}
set { _generatedCode = value; }
}
public override CompilerType CodeCompilerType
{
get
{
EnsureGeneratedCode();
CompilerType compilerType = GetDefaultCompilerTypeForLanguage(Host.CodeLanguage.LanguageName);
if (_isFullTrust != false && Host.DefaultDebugCompilation)
{
try
{
SetIncludeDebugInfoFlag(compilerType);
_isFullTrust = true;
}
catch (SecurityException)
{
_isFullTrust = false;
}
}
return compilerType;
}
}
public void AddVirtualPathDependency(string dependency)
{
if (_virtualPathDependencies == null)
{
// Initialize the collection containing the base dependencies
_virtualPathDependencies = new ArrayList(base.VirtualPathDependencies);
}
_virtualPathDependencies.Add(dependency);
}
public override Type GetGeneratedType(CompilerResults results)
{
return results.CompiledAssembly.GetType(String.Format(CultureInfo.CurrentCulture, "{0}.{1}", Host.DefaultNamespace, Host.DefaultClassName));
}
public override void GenerateCode(AssemblyBuilder assemblyBuilder)
{
GenerateCodeCore(new AssemblyBuilderWrapper(assemblyBuilder));
}
internal virtual void GenerateCodeCore(IAssemblyBuilder assemblyBuilder)
{
OnCodeGenerationStarted(assemblyBuilder);
assemblyBuilder.AddCodeCompileUnit(this, GeneratedCode);
assemblyBuilder.GenerateTypeFactory(String.Format(CultureInfo.InvariantCulture, "{0}.{1}", Host.DefaultNamespace, Host.DefaultClassName));
}
protected internal virtual TextReader InternalOpenReader()
{
return OpenReader();
}
protected internal virtual WebPageRazorHost CreateHost()
{
// Get the host from config
WebPageRazorHost configuredHost = GetHostFromConfig();
// Fire the event
CompilingPathEventArgs args = new CompilingPathEventArgs(VirtualPath, configuredHost);
OnBeforeCompilePath(args);
// Return the host provided in the args, which may have been changed by the handler
return args.Host;
}
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "This method performs significant work and a property would not be appropriate")]
protected internal virtual WebPageRazorHost GetHostFromConfig()
{
return WebRazorHostFactory.CreateHostFromConfig(VirtualPath);
}
protected virtual void OnBeforeCompilePath(CompilingPathEventArgs args)
{
EventHandler<CompilingPathEventArgs> handler = CompilingPath;
if (handler != null)
{
handler(this, args);
}
}
private void OnCodeGenerationStarted(IAssemblyBuilder assemblyBuilder)
{
_assemblyBuilder = assemblyBuilder;
EventHandler handler = _codeGenerationStartedInternal ?? CodeGenerationStarted;
if (handler != null)
{
handler(this, null);
}
}
private void OnCodeGenerationCompleted(CodeCompileUnit generatedCode)
{
EventHandler<CodeGenerationCompleteEventArgs> handler = _codeGenerationCompletedInternal ?? CodeGenerationCompleted;
if (handler != null)
{
handler(this, new CodeGenerationCompleteEventArgs(Host.VirtualPath, Host.PhysicalPath, generatedCode));
}
}
private void EnsureGeneratedCode()
{
if (_generatedCode == null)
{
RazorTemplateEngine engine = new RazorTemplateEngine(Host);
GeneratorResults results = null;
using (TextReader reader = InternalOpenReader())
{
results = engine.GenerateCode(reader, className: null, rootNamespace: null, sourceFileName: Host.PhysicalPath);
}
if (!results.Success)
{
throw CreateExceptionFromParserError(results.ParserErrors.Last(), VirtualPath);
}
_generatedCode = results.GeneratedCode;
// Run the code gen complete event
OnCodeGenerationCompleted(_generatedCode);
}
}
private static HttpParseException CreateExceptionFromParserError(RazorError error, string virtualPath)
{
return new HttpParseException(error.Message + Environment.NewLine, null, virtualPath, null, error.Location.LineIndex + 1);
}
[SuppressMessage("Microsoft.Security", "CA2141:TransparentMethodsMustNotSatisfyLinkDemandsFxCopRule", Justification = "We are catching the SecurityException to detect medium trust")]
private static void SetIncludeDebugInfoFlag(CompilerType compilerType)
{
compilerType.CompilerParameters.IncludeDebugInformation = true;
}
}
}
|