History

GSF.Web.Model: Refactored razor view, data context and web page controller implementations to use an external razor engine instance for wider use-case applicability

Ritchie Carroll committed 10 years ago

Commit 5b5cfbf1 parent ead8c0e9 files · +708 −534Browse files

Unified · Split

9 files
  1. Source/Libraries/GSF.Web/GSF.Web.csproj +4 −1
  2. Source/Libraries/GSF.Web/Hosting/WebPageController.cs +77 −95
  3. Source/Libraries/GSF.Web/Model/DataContext.cs +33 −47
  4. Source/Libraries/GSF.Web/Model/IRazorEngine.cs +49 −0
  5. Source/Libraries/GSF.Web/Model/IRazorView.cs +0 −112
  6. Source/Libraries/GSF.Web/Model/LanguageConstraint.cs +112 −0
  7. Source/Libraries/GSF.Web/Model/RazorEngine.cs +330 −0
  8. Source/Libraries/GSF.Web/Model/RazorView.cs +56 −279
  9. Source/Libraries/GSF.Web/Model/RazorViewResolutionMode.cs +47 −0
Source/Libraries/GSF.Web/GSF.Web.csproj+4−1
@@ -221,11 +221,14 @@ · 220 unmodified lines
221 <Compile Include="Hosting\WebPageController.cs" />221 <Compile Include="Hosting\WebPageController.cs" />
222 <Compile Include="IgnoreServicesSecurityModule.cs" />222 <Compile Include="IgnoreServicesSecurityModule.cs" />
223 <Compile Include="Model\DataContext.cs" />223 <Compile Include="Model\DataContext.cs" />
224 <Compile Include="Model\IRazorView.cs" />224 <Compile Include="Model\IRazorEngine.cs" />
225 <Compile Include="Model\IRecordOperationsHub.cs" />225 <Compile Include="Model\IRecordOperationsHub.cs" />
226 <Compile Include="Model\Label.cs" />226 <Compile Include="Model\Label.cs" />
227 <Compile Include="Model\IDLabel.cs" />227 <Compile Include="Model\IDLabel.cs" />
228 <Compile Include="Model\LanguageConstraint.cs" />
228 <Compile Include="Model\NamespaceDoc.cs" />229 <Compile Include="Model\NamespaceDoc.cs" />
230 <Compile Include="Model\RazorEngine.cs" />
231 <Compile Include="Model\RazorViewResolutionMode.cs" />
229 <Compile Include="Model\RecordOperationsCache.cs" />232 <Compile Include="Model\RecordOperationsCache.cs" />
230 <Compile Include="NamespaceDoc.cs" />233 <Compile Include="NamespaceDoc.cs" />
231 <Compile Include="Properties\AssemblyInfo.cs" />234 <Compile Include="Properties\AssemblyInfo.cs" />
Source/Libraries/GSF.Web/Hosting/WebPageController.cs+77−95
@@ -32,6 +32,7 @@ using System.Text; · 31 unmodified lines
32using System.Threading.Tasks;32using System.Threading.Tasks;
33using System.Web;33using System.Web;
34using System.Web.Http;34using System.Web.Http;
35using GSF.Data;
35using GSF.IO;36using GSF.IO;
36using GSF.IO.Checksums;37using GSF.IO.Checksums;
37using GSF.Reflection;38using GSF.Reflection;
@@ -58,15 +59,42 @@ namespace GSF.Web.Hosting · 20 unmodified lines
58 /// </summary>59 /// </summary>
59 public event EventHandler<string> StatusMessage;60 public event EventHandler<string> StatusMessage;
60 61
62 // Fields
63 private readonly string m_webRootPath;
64 private readonly IRazorEngine m_razorEngineCS;
65 private readonly IRazorEngine m_razorEngineVB;
66 private readonly ConcurrentDictionary<string, uint> m_etagCache;
67 private readonly SafeFileWatcher m_fileWatcher;
68 private bool m_disposed;
69
61 #endregion70 #endregion
62 71
63 #region [ Constructors ]72 #region [ Constructors ]
64 73
65 /// <summary>74 /// <summary>
66 /// Creates a new <see cref="WebPageController"/>.75 /// Creates a new <see cref="WebPageController"/>.
67 /// </summary>76 /// </summary>
68 public WebPageController()77 /// <param name="webRootPath">Root path for web page; defaults to template path for <paramref name="razorEngineCS"/>.</param>
78 /// <param name="razorEngineCS">Razor engine instance for .cshtml templates; uses default instance if not provided.</param>
79 /// <param name="razorEngineVB">Razor engine instance for .vbhtml templates; uses default instance if not provided.</param>
80 public WebPageController(string webRootPath = null, IRazorEngine razorEngineCS = null, IRazorEngine razorEngineVB = null)
69 {81 {
82 bool releaseMode = !AssemblyInfo.EntryAssembly.Debuggable;
83 m_razorEngineCS = razorEngineCS ?? (releaseMode ? RazorEngine<CSharp>.Default : RazorEngine<CSharpDebug>.Default as IRazorEngine);
84 m_razorEngineVB = razorEngineVB ?? (releaseMode ? RazorEngine<VisualBasic>.Default : RazorEngine<VisualBasicDebug>.Default as IRazorEngine);
85 m_webRootPath = FilePath.AddPathSuffix(webRootPath ?? m_razorEngineCS.TemplatePath);
86 m_etagCache = new ConcurrentDictionary<string, uint>(StringComparer.InvariantCultureIgnoreCase);
87
88 m_fileWatcher = new SafeFileWatcher(m_webRootPath)
89 {
90 IncludeSubdirectories = true,
91 EnableRaisingEvents = true
92 };
93
94 m_fileWatcher.Changed += m_fileWatcher_FileChange;
95 m_fileWatcher.Deleted += m_fileWatcher_FileChange;
96 m_fileWatcher.Renamed += m_fileWatcher_FileChange;
97
70 DefaultWebPage = "index.html";98 DefaultWebPage = "index.html";
71 ClientCacheEnabled = true;99 ClientCacheEnabled = true;
72 }100 }
@@ -74,7 +102,7 @@ namespace GSF.Web.Hosting · 1 unmodified line
74 #endregion102 #endregion
75 103
76 #region [ Properties ]104 #region [ Properties ]
77 105
78 /// <summary>106 /// <summary>
79 /// Gets or sets default web page to use for this <see cref="WebPageController"/>.107 /// Gets or sets default web page to use for this <see cref="WebPageController"/>.
80 /// </summary>108 /// </summary>
@@ -85,7 +113,7 @@ namespace GSF.Web.Hosting · 4 unmodified lines
85 }113 }
86 114
87 /// <summary>115 /// <summary>
88 /// Gets or sets the Razor model instance for this <see cref="WebPageController"/>.116 /// Gets or sets the <see cref="RazorView"/> model instance for this <see cref="WebPageController"/>, if any.
89 /// </summary>117 /// </summary>
90 public object RazorModel118 public object RazorModel
91 {119 {
@@ -94,7 +122,7 @@ namespace GSF.Web.Hosting · 2 unmodified lines
94 }122 }
95 123
96 /// <summary>124 /// <summary>
97 /// Gets or sets the Razor model <see cref="Type"/> for this <see cref="WebPageController"/>.125 /// Gets or sets the <see cref="RazorView"/> model <see cref="Type"/> for this <see cref="WebPageController"/>, if any.
98 /// </summary>126 /// </summary>
99 public Type RazorModelType127 public Type RazorModelType
100 {128 {
@@ -102,6 +130,15 @@ namespace GSF.Web.Hosting · 1 unmodified line
102 set;130 set;
103 }131 }
104 132
133 /// <summary>
134 /// Gets or sets data connection to provide to <see cref="RazorView"/> instances in this <see cref="WebPageController"/>, if any.
135 /// </summary>
136 public AdoDataConnection RazorConnection
137 {
138 get;
139 set;
140 }
141
105 /// <summary>142 /// <summary>
106 /// Gets or sets flag that determines if cache control is enabled for browser clients; default to <c>true</c>.143 /// Gets or sets flag that determines if cache control is enabled for browser clients; default to <c>true</c>.
107 /// </summary>144 /// </summary>
@@ -115,6 +152,27 @@ namespace GSF.Web.Hosting · 7 unmodified lines
115 152
116 #region [ Methods ]153 #region [ Methods ]
117 154
155 /// <summary>
156 /// Releases the unmanaged resources used by the <see cref="WebPageController"/> object and optionally releases the managed resources.
157 /// </summary>
158 /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
159 protected override void Dispose(bool disposing)
160 {
161 if (!m_disposed)
162 {
163 try
164 {
165 if (disposing)
166 m_fileWatcher?.Dispose();
167 }
168 finally
169 {
170 m_disposed = true; // Prevent duplicate dispose.
171 base.Dispose(disposing); // Call base class Dispose().
172 }
173 }
174 }
175
118 /// <summary>176 /// <summary>
119 /// Default page request handler.177 /// Default page request handler.
120 /// </summary>178 /// </summary>
@@ -157,22 +215,22 @@ namespace GSF.Web.Hosting · 36 unmodified lines
157 switch (fileExtension)215 switch (fileExtension)
158 {216 {
159 case ".cshtml":217 case ".cshtml":
160 content = await s_razorViewCS(pageName, RazorModel, RazorModelType, OnExecutionException).ExecuteAsync(Request, postData);218 content = await new RazorView(m_razorEngineCS, pageName, RazorModel, RazorModelType, RazorConnection, OnExecutionException).ExecuteAsync(Request, postData);
161 response.Content = new StringContent(content, Encoding.UTF8, "text/html");219 response.Content = new StringContent(content, Encoding.UTF8, "text/html");
162 break;220 break;
163 case ".vbhtml":221 case ".vbhtml":
164 content = await s_razorViewVB(pageName, RazorModel, RazorModelType, OnExecutionException).ExecuteAsync(Request, postData);222 content = await new RazorView(m_razorEngineVB, pageName, RazorModel, RazorModelType, RazorConnection, OnExecutionException).ExecuteAsync(Request, postData);
165 response.Content = new StringContent(content, Encoding.UTF8, "text/html");223 response.Content = new StringContent(content, Encoding.UTF8, "text/html");
166 break;224 break;
167 default:225 default:
168 string fileName = FilePath.GetAbsolutePath($"{FilePath.AddPathSuffix(s_templatePath)}{pageName.Replace('/', Path.DirectorySeparatorChar)}");226 string fileName = FilePath.GetAbsolutePath($"{m_webRootPath}{pageName.Replace('/', Path.DirectorySeparatorChar)}");
169 227
170 if (File.Exists(fileName))228 if (File.Exists(fileName))
171 {229 {
172 FileStream fileData = null;230 FileStream fileData = null;
173 uint responseHash = 0;231 uint responseHash = 0;
174 232
175 if (ClientCacheEnabled && !s_etagCache.TryGetValue(fileName, out responseHash))233 if (ClientCacheEnabled && !m_etagCache.TryGetValue(fileName, out responseHash))
176 {234 {
177 // Calculate check-sum for file235 // Calculate check-sum for file
178 await Task.Run(() =>236 await Task.Run(() =>
@@ -191,7 +249,7 @@ namespace GSF.Web.Hosting · 12 unmodified lines
191 }249 }
192 250
193 responseHash = calculatedHash.Value;251 responseHash = calculatedHash.Value;
194 s_etagCache.TryAdd(fileName, responseHash);252 m_etagCache.TryAdd(fileName, responseHash);
195 fileData.Seek(0, SeekOrigin.Begin);253 fileData.Seek(0, SeekOrigin.Begin);
196 254
197 OnStatusMessage($"Cache [{responseHash}] added for file \"{fileName}\"");255 OnStatusMessage($"Cache [{responseHash}] added for file \"{fileName}\"");
@@ -200,7 +258,7 @@ namespace GSF.Web.Hosting · 2 unmodified lines
200 258
201 if (PublishResponseContent(response, responseHash))259 if (PublishResponseContent(response, responseHash))
202 {260 {
203 if ((object)fileData == null)261 if (fileData == null)
204 fileData = File.OpenRead(fileName);262 fileData = File.OpenRead(fileName);
205 263
206 response.Content = await Task.Run(() => new StreamContent(fileData));264 response.Content = await Task.Run(() => new StreamContent(fileData));
@@ -259,6 +317,14 @@ namespace GSF.Web.Hosting · 52 unmodified lines
259 StatusMessage?.Invoke(this, message);317 StatusMessage?.Invoke(this, message);
260 }318 }
261 319
320 private void m_fileWatcher_FileChange(object sender, FileSystemEventArgs e)
321 {
322 uint responseHash;
323
324 if (m_etagCache.TryRemove(e.FullPath, out responseHash))
325 OnStatusMessage($"Cache [{responseHash}] cleared for file \"{e.FullPath}\"");
326 }
327
262 #region [ Sub-folder Handlers ]328 #region [ Sub-folder Handlers ]
263 329
264 /// <summary>330 /// <summary>
@@ -409,89 +475,5 @@ namespace GSF.Web.Hosting · 144 unmodified lines
409 #endregion475 #endregion
410 476
411 #endregion477 #endregion
412
413 #region [ Static ]
414
415 // Static Events
416
417 /// <summary>
418 /// Exposes any execution exceptions that occur during static <see cref="WebPageController"/> initialization.
419 /// </summary>
420 public static event EventHandler<Exception> InitializationExceptions;
421
422 /// <summary>
423 /// Exposes any status messages that get reported from static <see cref="WebPageController"/> initialization.
424 /// </summary>
425 public static event EventHandler<string> InitializationMessages;
426
427 // Static Fields
428 private static readonly string s_templatePath;
429 private static readonly Func<string, object, Type, Action<Exception>, IRazorView> s_razorViewCS;
430 private static readonly Func<string, object, Type, Action<Exception>, IRazorView> s_razorViewVB;
431 private static readonly ConcurrentDictionary<string, uint> s_etagCache;
432 private static readonly FileSystemWatcher s_fileWatcher;
433
434 // Static Constructor
435 static WebPageController()
436 {
437 bool isDebugMode = AssemblyInfo.EntryAssembly.Debuggable;
438
439 if (isDebugMode)
440 {
441 s_templatePath = RazorView<CSharpDebug>.TemplatePath;
442 s_razorViewCS = (templateName, model, modelType, exceptionHandler) => new RazorView<CSharpDebug>(templateName, model, modelType, exceptionHandler);
443 s_razorViewVB = (templateName, model, modelType, exceptionHandler) => new RazorView<VisualBasicDebug>(templateName, model, modelType, exceptionHandler);
444 }
445 else
446 {
447 s_templatePath = RazorView<CSharp>.TemplatePath;
448 s_razorViewCS = (templateName, model, modelType, exceptionHandler) => new RazorView<CSharp>(templateName, model, modelType, exceptionHandler);
449 s_razorViewVB = (templateName, model, modelType, exceptionHandler) => new RazorView<VisualBasic>(templateName, model, modelType, exceptionHandler);
450 }
451
452 s_etagCache = new ConcurrentDictionary<string, uint>(StringComparer.InvariantCultureIgnoreCase);
453
454 s_fileWatcher = new FileSystemWatcher(s_templatePath)
455 {
456 IncludeSubdirectories = true,
457 EnableRaisingEvents = true
458 };
459
460 s_fileWatcher.Changed += s_fileWatcher_FileChange;
461 s_fileWatcher.Deleted += s_fileWatcher_FileChange;
462 s_fileWatcher.Renamed += s_fileWatcher_FileChange;
463
464
465 if (isDebugMode)
466 {
467 RazorView<CSharpDebug>.PreCompile(OnInitializationExceptions);
468 RazorView<VisualBasicDebug>.PreCompile(OnInitializationExceptions);
469 }
470 else
471 {
472 RazorView<CSharp>.PreCompile(OnInitializationExceptions);
473 RazorView<VisualBasic>.PreCompile(OnInitializationExceptions);
474 }
475 }
476
477 private static void s_fileWatcher_FileChange(object sender, FileSystemEventArgs e)
478 {
479 uint responseHash;
480
481 if (s_etagCache.TryRemove(e.FullPath, out responseHash))
482 OnInitializationMessages($"Cache [{responseHash}] cleared for file \"{e.FullPath}\"");
483 }
484
485 private static void OnInitializationExceptions(Exception exception)
486 {
487 InitializationExceptions?.Invoke(null, exception);
488 }
489
490 private static void OnInitializationMessages(string message)
491 {
492 InitializationMessages?.Invoke(null, message);
493 }
494
495 #endregion
496 }478 }
497}479}
Source/Libraries/GSF.Web/Model/DataContext.cs+33−47
@@ -41,42 +41,19 @@ using RazorEngine.Templating; · 40 unmodified lines
41namespace GSF.Web.Model41namespace GSF.Web.Model
42{42{
43 /// <summary>43 /// <summary>
44 /// Defines a default data context object based on embedded resources.44 /// Defines a data context for Razor views.
45 /// </summary>45 /// </summary>
46 public class DataContext : DataContext<CSharpEmbeddedResource>46 /// <remarks>
47 {47 /// This class is used by views to render HTML form input templates, paged view model configurations,
48 /// <summary>48 /// provide access to modeled table operations and general database access.
49 /// Creates a new <see cref="DataContext"/>.49 /// </remarks>
50 /// </summary>50 public class DataContext : IDisposable
51 /// <param name="connection"><see cref="AdoDataConnection"/> to use; defaults to a new connection.</param>
52 /// <param name="disposeConnection">Set to <c>true</c> to dispose the provided <paramref name="connection"/>.</param>
53 /// <param name="exceptionHandler">Delegate to handle exceptions.</param>
54 public DataContext(AdoDataConnection connection = null, bool disposeConnection = false, Action<Exception> exceptionHandler = null) :
55 base(connection, disposeConnection, exceptionHandler)
56 {
57 }
58
59 /// <summary>
60 /// Creates a new <see cref="DataContext"/> using the specified <paramref name="settingsCategory"/>.
61 /// </summary>
62 /// <param name="settingsCategory">Setting category that contains the connection settings.</param>
63 /// <param name="exceptionHandler">Delegate to handle exceptions.</param>
64 public DataContext(string settingsCategory, Action<Exception> exceptionHandler = null) :
65 base(settingsCategory, exceptionHandler)
66 {
67 }
68 }
69
70 /// <summary>
71 /// Defines a data context for modeled tables.
72 /// </summary>
73 /// <typeparam name="TLanguage"><see cref="LanguageConstraint"/> type to use for Razor views.</typeparam>
74 public class DataContext<TLanguage> : IDisposable where TLanguage : LanguageConstraint, new()
75 {51 {
76 #region [ Members ]52 #region [ Members ]
77 53
78 // Fields54 // Fields
79 private AdoDataConnection m_connection;55 private AdoDataConnection m_connection;
56 private readonly IRazorEngine m_razorEngine;
80 private readonly Dictionary<Type, object> m_tableOperations;57 private readonly Dictionary<Type, object> m_tableOperations;
81 private readonly Action<Exception> m_exceptionHandler;58 private readonly Action<Exception> m_exceptionHandler;
82 private readonly Dictionary<string, Tuple<string, string>> m_fieldValidationParameters;59 private readonly Dictionary<string, Tuple<string, string>> m_fieldValidationParameters;
@@ -98,14 +75,16 @@ namespace GSF.Web.Model · 15 unmodified lines
98 #region [ Constructors ]75 #region [ Constructors ]
99 76
100 /// <summary>77 /// <summary>
101 /// Creates a new <see cref="DataContext{TLanguage}"/>.78 /// Creates a new <see cref="DataContext"/>.
102 /// </summary>79 /// </summary>
103 /// <param name="connection"><see cref="AdoDataConnection"/> to use; defaults to a new connection.</param>80 /// <param name="connection"><see cref="AdoDataConnection"/> to use; defaults to a new connection.</param>
104 /// <param name="disposeConnection">Set to <c>true</c> to dispose the provided <paramref name="connection"/>.</param>81 /// <param name="disposeConnection">Set to <c>true</c> to dispose the provided <paramref name="connection"/>.</param>
82 /// <param name="razorEngine">Razor engine instance to use for data context; set to <c>null</c> to use default embedded resources instance.</param>
105 /// <param name="exceptionHandler">Delegate to handle exceptions.</param>83 /// <param name="exceptionHandler">Delegate to handle exceptions.</param>
106 public DataContext(AdoDataConnection connection = null, bool disposeConnection = false, Action<Exception> exceptionHandler = null)84 public DataContext(AdoDataConnection connection = null, bool disposeConnection = false, IRazorEngine razorEngine = null, Action<Exception> exceptionHandler = null)
107 {85 {
108 m_connection = connection;86 m_connection = connection;
87 m_razorEngine = razorEngine ?? RazorEngine<CSharpEmbeddedResource>.Default;
109 m_tableOperations = new Dictionary<Type, object>();88 m_tableOperations = new Dictionary<Type, object>();
110 m_exceptionHandler = exceptionHandler;89 m_exceptionHandler = exceptionHandler;
111 m_fieldValidationParameters = new Dictionary<string, Tuple<string, string>>();90 m_fieldValidationParameters = new Dictionary<string, Tuple<string, string>>();
@@ -117,12 +96,14 @@ namespace GSF.Web.Model · 5 unmodified lines
117 }96 }
118 97
119 /// <summary>98 /// <summary>
120 /// Creates a new <see cref="DataContext{TLanguage}"/> using the specified <paramref name="settingsCategory"/>.99 /// Creates a new <see cref="DataContext"/> using the specified <paramref name="settingsCategory"/>.
121 /// </summary>100 /// </summary>
122 /// <param name="settingsCategory">Setting category that contains the connection settings.</param>101 /// <param name="settingsCategory">Setting category that contains the connection settings.</param>
102 /// <param name="razorEngine">Razor engine instance to use for data context; set to <c>null</c> to use default embedded resources instance.</param>
123 /// <param name="exceptionHandler">Delegate to handle exceptions.</param>103 /// <param name="exceptionHandler">Delegate to handle exceptions.</param>
124 public DataContext(string settingsCategory, Action<Exception> exceptionHandler = null)104 public DataContext(string settingsCategory, IRazorEngine razorEngine = null, Action<Exception> exceptionHandler = null)
125 {105 {
106 m_razorEngine = razorEngine ?? RazorEngine<CSharpEmbeddedResource>.Default;
126 m_tableOperations = new Dictionary<Type, object>();107 m_tableOperations = new Dictionary<Type, object>();
127 m_exceptionHandler = exceptionHandler;108 m_exceptionHandler = exceptionHandler;
128 m_fieldValidationParameters = new Dictionary<string, Tuple<string, string>>();109 m_fieldValidationParameters = new Dictionary<string, Tuple<string, string>>();
@@ -137,7 +118,12 @@ namespace GSF.Web.Model · 8 unmodified lines
137 #region [ Properties ]118 #region [ Properties ]
138 119
139 /// <summary>120 /// <summary>
140 /// Gets the <see cref="AdoDataConnection"/> for this <see cref="DataContext{TLanguage}"/>.121 /// Gets reference to <see cref="IRazorEngine"/> used by this <see cref="DataContext"/>.
122 /// </summary>
123 public IRazorEngine RazorEngine => m_razorEngine;
124
125 /// <summary>
126 /// Gets the <see cref="AdoDataConnection"/> for this <see cref="DataContext"/>, creating a new one if needed.
141 /// </summary>127 /// </summary>
142 public AdoDataConnection Connection => m_connection ?? (m_connection = new AdoDataConnection(m_settingsCategory));128 public AdoDataConnection Connection => m_connection ?? (m_connection = new AdoDataConnection(m_settingsCategory));
143 129
@@ -178,7 +164,7 @@ namespace GSF.Web.Model · 34 unmodified lines
178 {164 {
179 get165 get
180 {166 {
181 return m_addDateFieldTemplate ?? (m_addDateFieldTemplate = $"{RazorView<TLanguage>.TemplatePath}AddDateField.cshtml");167 return m_addDateFieldTemplate ?? (m_addDateFieldTemplate = $"{m_razorEngine.TemplatePath}AddDateField.cshtml");
182 }168 }
183 set169 set
184 {170 {
@@ -193,7 +179,7 @@ namespace GSF.Web.Model · 8 unmodified lines
193 {179 {
194 get180 get
195 {181 {
196 return m_addInputFieldTemplate ?? (m_addInputFieldTemplate = $"{RazorView<TLanguage>.TemplatePath}AddInputField.cshtml");182 return m_addInputFieldTemplate ?? (m_addInputFieldTemplate = $"{m_razorEngine.TemplatePath}AddInputField.cshtml");
197 }183 }
198 set184 set
199 {185 {
@@ -208,7 +194,7 @@ namespace GSF.Web.Model · 8 unmodified lines
208 {194 {
209 get195 get
210 {196 {
211 return m_addTextAreaFieldTemplate ?? (m_addTextAreaFieldTemplate = $"{RazorView<TLanguage>.TemplatePath}AddTextAreaField.cshtml");197 return m_addTextAreaFieldTemplate ?? (m_addTextAreaFieldTemplate = $"{m_razorEngine.TemplatePath}AddTextAreaField.cshtml");
212 }198 }
213 set199 set
214 {200 {
@@ -223,7 +209,7 @@ namespace GSF.Web.Model · 8 unmodified lines
223 {209 {
224 get210 get
225 {211 {
226 return m_addSelectFieldTemplate ?? (m_addSelectFieldTemplate = $"{RazorView<TLanguage>.TemplatePath}AddSelectField.cshtml");212 return m_addSelectFieldTemplate ?? (m_addSelectFieldTemplate = $"{m_razorEngine.TemplatePath}AddSelectField.cshtml");
227 }213 }
228 set214 set
229 {215 {
@@ -238,7 +224,7 @@ namespace GSF.Web.Model · 8 unmodified lines
238 {224 {
239 get225 get
240 {226 {
241 return m_addCheckBoxFieldTemplate ?? (m_addCheckBoxFieldTemplate = $"{RazorView<TLanguage>.TemplatePath}AddCheckBoxField.cshtml");227 return m_addCheckBoxFieldTemplate ?? (m_addCheckBoxFieldTemplate = $"{m_razorEngine.TemplatePath}AddCheckBoxField.cshtml");
242 }228 }
243 set229 set
244 {230 {
@@ -251,7 +237,7 @@ namespace GSF.Web.Model · 6 unmodified lines
251 #region [ Methods ]237 #region [ Methods ]
252 238
253 /// <summary>239 /// <summary>
254 /// Releases all the resources used by the <see cref="DataContext{TLanguage}"/> object.240 /// Releases all the resources used by the <see cref="DataContext"/> object.
255 /// </summary>241 /// </summary>
256 public void Dispose()242 public void Dispose()
257 {243 {
@@ -260,7 +246,7 @@ namespace GSF.Web.Model · 2 unmodified lines
260 }246 }
261 247
262 /// <summary>248 /// <summary>
263 /// Releases the unmanaged resources used by the <see cref="DataContext{TLanguage}"/> object and optionally releases the managed resources.249 /// Releases the unmanaged resources used by the <see cref="DataContext"/> object and optionally releases the managed resources.
264 /// </summary>250 /// </summary>
265 /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>251 /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
266 protected virtual void Dispose(bool disposing)252 protected virtual void Dispose(bool disposing)
@@ -786,7 +772,7 @@ namespace GSF.Web.Model · 519 unmodified lines
786 /// <returns>Generated HTML for new date based input field based on specified parameters.</returns>772 /// <returns>Generated HTML for new date based input field based on specified parameters.</returns>
787 public string AddDateField(string fieldName, bool required, int maxLength = 0, string inputType = null, string fieldLabel = null, string fieldID = null, string groupDataBinding = null, string labelDataBinding = null, string requiredDataBinding = null, string customDataBinding = null, string dependencyFieldName = null, string toolTip = null, bool initialFocus = false)773 public string AddDateField(string fieldName, bool required, int maxLength = 0, string inputType = null, string fieldLabel = null, string fieldID = null, string groupDataBinding = null, string labelDataBinding = null, string requiredDataBinding = null, string customDataBinding = null, string dependencyFieldName = null, string toolTip = null, bool initialFocus = false)
788 {774 {
789 RazorView<TLanguage> addDateFieldTemplate = new RazorView<TLanguage>(AddDateFieldTemplate, m_exceptionHandler);775 RazorView addDateFieldTemplate = new RazorView(m_razorEngine, AddDateFieldTemplate, m_exceptionHandler);
790 DynamicViewBag viewBag = addDateFieldTemplate.ViewBag;776 DynamicViewBag viewBag = addDateFieldTemplate.ViewBag;
791 777
792 if (string.IsNullOrEmpty(fieldID))778 if (string.IsNullOrEmpty(fieldID))
@@ -895,7 +881,7 @@ namespace GSF.Web.Model · 102 unmodified lines
895 /// <returns>Generated HTML for new input field based on specified parameters.</returns>881 /// <returns>Generated HTML for new input field based on specified parameters.</returns>
896 public string AddInputField(string fieldName, bool required, int maxLength = 0, string inputType = null, string fieldLabel = null, string fieldID = null, string groupDataBinding = null, string labelDataBinding = null, string requiredDataBinding = null, string customDataBinding = null, string dependencyFieldName = null, string toolTip = null, bool initialFocus = false, bool enableHotLinks = true)882 public string AddInputField(string fieldName, bool required, int maxLength = 0, string inputType = null, string fieldLabel = null, string fieldID = null, string groupDataBinding = null, string labelDataBinding = null, string requiredDataBinding = null, string customDataBinding = null, string dependencyFieldName = null, string toolTip = null, bool initialFocus = false, bool enableHotLinks = true)
897 {883 {
898 RazorView<TLanguage> addInputFieldTemplate = new RazorView<TLanguage>(AddInputFieldTemplate, m_exceptionHandler);884 RazorView addInputFieldTemplate = new RazorView(m_razorEngine, AddInputFieldTemplate, m_exceptionHandler);
899 DynamicViewBag viewBag = addInputFieldTemplate.ViewBag;885 DynamicViewBag viewBag = addInputFieldTemplate.ViewBag;
900 886
901 if (string.IsNullOrEmpty(fieldID))887 if (string.IsNullOrEmpty(fieldID))
@@ -998,7 +984,7 @@ namespace GSF.Web.Model · 96 unmodified lines
998 /// <returns>Generated HTML for new text area field based on specified parameters.</returns>984 /// <returns>Generated HTML for new text area field based on specified parameters.</returns>
999 public string AddTextAreaField(string fieldName, bool required, int maxLength = 0, int rows = 2, string fieldLabel = null, string fieldID = null, string groupDataBinding = null, string labelDataBinding = null, string requiredDataBinding = null, string customDataBinding = null, string dependencyFieldName = null, string toolTip = null, bool initialFocus = false, bool enableHotLinks = true)985 public string AddTextAreaField(string fieldName, bool required, int maxLength = 0, int rows = 2, string fieldLabel = null, string fieldID = null, string groupDataBinding = null, string labelDataBinding = null, string requiredDataBinding = null, string customDataBinding = null, string dependencyFieldName = null, string toolTip = null, bool initialFocus = false, bool enableHotLinks = true)
1000 {986 {
1001 RazorView<TLanguage> addTextAreaTemplate = new RazorView<TLanguage>(AddTextAreaFieldTemplate, m_exceptionHandler);987 RazorView addTextAreaTemplate = new RazorView(m_razorEngine, AddTextAreaFieldTemplate, m_exceptionHandler);
1002 DynamicViewBag viewBag = addTextAreaTemplate.ViewBag;988 DynamicViewBag viewBag = addTextAreaTemplate.ViewBag;
1003 989
1004 if (string.IsNullOrEmpty(fieldID))990 if (string.IsNullOrEmpty(fieldID))
@@ -1087,7 +1073,7 @@ namespace GSF.Web.Model · 82 unmodified lines
1087 /// <returns>Generated HTML for new text field based on specified parameters.</returns>1073 /// <returns>Generated HTML for new text field based on specified parameters.</returns>
1088 public string AddSelectField<TOption>(string fieldName, bool required, string optionValueFieldName, string optionLabelFieldName = null, string optionSortFieldName = null, string fieldLabel = null, string fieldID = null, string groupDataBinding = null, string labelDataBinding = null, string customDataBinding = null, string dependencyFieldName = null, string optionDataBinding = null, string toolTip = null, bool initialFocus = false, RecordRestriction restriction = null) where TOption : class, new()1074 public string AddSelectField<TOption>(string fieldName, bool required, string optionValueFieldName, string optionLabelFieldName = null, string optionSortFieldName = null, string fieldLabel = null, string fieldID = null, string groupDataBinding = null, string labelDataBinding = null, string customDataBinding = null, string dependencyFieldName = null, string optionDataBinding = null, string toolTip = null, bool initialFocus = false, RecordRestriction restriction = null) where TOption : class, new()
1089 {1075 {
1090 RazorView<TLanguage> addSelectFieldTemplate = new RazorView<TLanguage>(AddSelectFieldTemplate, m_exceptionHandler);1076 RazorView addSelectFieldTemplate = new RazorView(m_razorEngine, AddSelectFieldTemplate, m_exceptionHandler);
1091 DynamicViewBag viewBag = addSelectFieldTemplate.ViewBag;1077 DynamicViewBag viewBag = addSelectFieldTemplate.ViewBag;
1092 TableOperations<TOption> optionTableOperations = Table<TOption>();1078 TableOperations<TOption> optionTableOperations = Table<TOption>();
1093 Dictionary<string, string> options = new Dictionary<string, string>();1079 Dictionary<string, string> options = new Dictionary<string, string>();
@@ -1169,7 +1155,7 @@ namespace GSF.Web.Model · 75 unmodified lines
1169 /// <returns>Generated HTML for new check box field based on specified parameters.</returns>1155 /// <returns>Generated HTML for new check box field based on specified parameters.</returns>
1170 public string AddCheckBoxField(string fieldName, string fieldLabel = null, string fieldID = null, string groupDataBinding = null, string labelDataBinding = null, string customDataBinding = null, string dependencyFieldName = null, string toolTip = null, bool initialFocus = false)1156 public string AddCheckBoxField(string fieldName, string fieldLabel = null, string fieldID = null, string groupDataBinding = null, string labelDataBinding = null, string customDataBinding = null, string dependencyFieldName = null, string toolTip = null, bool initialFocus = false)
1171 {1157 {
1172 RazorView<TLanguage> addCheckBoxFieldTemplate = new RazorView<TLanguage>(AddCheckBoxFieldTemplate, m_exceptionHandler);1158 RazorView addCheckBoxFieldTemplate = new RazorView(m_razorEngine, AddCheckBoxFieldTemplate, m_exceptionHandler);
1173 DynamicViewBag viewBag = addCheckBoxFieldTemplate.ViewBag;1159 DynamicViewBag viewBag = addCheckBoxFieldTemplate.ViewBag;
1174 1160
1175 if (string.IsNullOrEmpty(fieldID))1161 if (string.IsNullOrEmpty(fieldID))
Source/Libraries/GSF.Web/Model/IRazorEngine.cs+49−0
@@ -0,0 +1,49 @@
1//******************************************************************************************************
2// IRazorEngine.cs - Gbtc
3//
4// Copyright © 2016, Grid Protection Alliance. All Rights Reserved.
5//
6// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this
9// file except in compliance with the License. You may obtain a copy of the License at:
10//
11// http://opensource.org/licenses/MIT
12//
13// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15// License for the specific language governing permissions and limitations.
16//
17// Code Modification History:
18// ----------------------------------------------------------------------------------------------------
19// 05/05/2016 - J. Ritchie Carroll
20// Generated original version of source code.
21//
22//******************************************************************************************************
23
24using System;
25using System.Threading.Tasks;
26using RazorEngine.Templating;
27
28namespace GSF.Web.Model
29{
30 /// <summary>
31 /// Defines an interface for <see cref="RazorEngine{TLanguage}"/> implementations.
32 /// </summary>
33 public interface IRazorEngine : IRazorEngineService
34 {
35 /// <summary>
36 /// Gets the template path defined for this <see cref="IRazorEngine"/>.
37 /// </summary>
38 string TemplatePath
39 {
40 get;
41 }
42
43 /// <summary>
44 /// Kicks off a task to pre-compile Razor templates.
45 /// </summary>
46 /// <param name="exceptionHandler">Exception handler used to report issues, if any.</param>
47 Task PreCompile(Action<Exception> exceptionHandler = null);
48 }
49}
Source/Libraries/GSF.Web/Model/IRazorView.cs+0−112
@@ -1,112 +0,0 @@
1//******************************************************************************************************
2// IRazorView.cs - Gbtc
3//
4// Copyright © 2016, Grid Protection Alliance. All Rights Reserved.
5//
6// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this
9// file except in compliance with the License. You may obtain a copy of the License at:
10//
11// http://opensource.org/licenses/MIT
12//
13// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15// License for the specific language governing permissions and limitations.
16//
17// Code Modification History:
18// ----------------------------------------------------------------------------------------------------
19// 05/05/2016 - J. Ritchie Carroll
20// Generated original version of source code.
21//
22//******************************************************************************************************
23
24using System;
25using System.Collections.Generic;
26using System.Net.Http;
27using System.Threading.Tasks;
28
29namespace GSF.Web.Model
30{
31 /// <summary>
32 /// Defines an interface for <see cref="RazorView{TLanguage}"/> implementations.
33 /// </summary>
34 public interface IRazorView
35 {
36 /// <summary>
37 /// Gets or sets name of template file.
38 /// </summary>
39 string TemplateName
40 {
41 get; set;
42 }
43
44 /// <summary>
45 /// Gets or sets reference to model to use when rendering template.
46 /// </summary>
47 object Model
48 {
49 get; set;
50 }
51
52 /// <summary>
53 /// Gets or sets type of <see cref="Model"/>.
54 /// </summary>
55 Type ModelType
56 {
57 get; set;
58 }
59
60 /// <summary>
61 /// Gets or sets delegate used to handle exceptions.
62 /// </summary>
63 Action<Exception> ExceptionHandler
64 {
65 get; set;
66 }
67
68 /// <summary>
69 /// Gets reference to view bag used when rendering template.
70 /// </summary>
71 dynamic ViewBag
72 {
73 get;
74 }
75
76 /// <summary>
77 /// Gets query string parameter specified by <paramref name="key"/>.
78 /// </summary>
79 /// <param name="key">Name of query string parameter to retrieve.</param>
80 /// <returns>Query string parameter specified by <paramref name="key"/>.</returns>
81 string this[string key]
82 {
83 get;
84 }
85
86 /// <summary>
87 /// Gets a dictionary of query string parameters passed to rendered view.
88 /// </summary>
89 Dictionary<string, string> Parameters
90 {
91 get;
92 }
93
94 /// <summary>
95 /// Compiles and executes view template.
96 /// </summary>
97 /// <returns>Rendered result.</returns>
98 string Execute();
99
100 /// <summary>
101 /// Compiles and executes view template for specified request message and post data.
102 /// </summary>
103 /// <returns>Rendered result.</returns>
104 string Execute(HttpRequestMessage requestMessage, dynamic postData);
105
106 /// <summary>
107 /// Asynchronously compiles and executes view template for specified request message and post data.
108 /// </summary>
109 /// <returns>Task that will provide rendered result.</returns>
110 Task ExecuteAsync(HttpRequestMessage requestMessage, dynamic postData);
111 }
112}
Source/Libraries/GSF.Web/Model/LanguageConstraint.cs+112−0
@@ -0,0 +1,112 @@
1//******************************************************************************************************
2// LanguageConstraint.cs - Gbtc
3//
4// Copyright � 2016, Grid Protection Alliance. All Rights Reserved.
5//
6// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this
9// file except in compliance with the License. You may obtain a copy of the License at:
10//
11// http://opensource.org/licenses/MIT
12//
13// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15// License for the specific language governing permissions and limitations.
16//
17// Code Modification History:
18// ----------------------------------------------------------------------------------------------------
19// 05/05/2016 - J. Ritchie Carroll
20// Generated original version of source code.
21//
22//******************************************************************************************************
23
24using RazorEngine;
25
26namespace GSF.Web.Model
27{
28 /// <summary>
29 /// Defines a language constraint for a <see cref="RazorEngine{TLanguage}"/>.
30 /// </summary>
31 public abstract class LanguageConstraint
32 {
33 /// <summary>
34 /// Gets target language for the <see cref="LanguageConstraint"/> implementation.
35 /// </summary>
36 public abstract Language TargetLanguage
37 {
38 get;
39 }
40
41 /// <summary>
42 /// Gets resolution mode for <see cref="RazorEngine{TLanguage}"/> views.
43 /// </summary>
44 public virtual RazorViewResolutionMode ResolutionMode => RazorViewResolutionMode.ResolvePath;
45 }
46
47 /// <summary>
48 /// Defines a C# based language constraint.
49 /// </summary>
50 public class CSharp : LanguageConstraint
51 {
52 /// <summary>
53 /// Gets target language for the <see cref="LanguageConstraint"/> implementation - C#.
54 /// </summary>
55 public override Language TargetLanguage => Language.CSharp;
56 }
57
58 /// <summary>
59 /// Defines a C# based language constraint in debug mode.
60 /// </summary>
61 public class CSharpDebug : CSharp
62 {
63 /// <summary>
64 /// Gets resolution mode for <see cref="RazorEngine{TLanguage}"/> views - watching resolve path for debugging operations.
65 /// </summary>
66 public override RazorViewResolutionMode ResolutionMode => RazorViewResolutionMode.WatchingResolvePath;
67 }
68
69 /// <summary>
70 /// Defines a C# based language constraint for embedded resources.
71 /// </summary>
72 public class CSharpEmbeddedResource : CSharp
73 {
74 /// <summary>
75 /// Gets resolution mode for <see cref="RazorEngine{TLanguage}"/> views - embedded resources.
76 /// </summary>
77 public override RazorViewResolutionMode ResolutionMode => RazorViewResolutionMode.EmbeddedResource;
78 }
79
80 /// <summary>
81 /// Defines a Visual Basic based language constraint.
82 /// </summary>
83 public class VisualBasic : LanguageConstraint
84 {
85 /// <summary>
86 /// Gets target language for the <see cref="LanguageConstraint"/> implementation - Visual Basic.
87 /// </summary>
88 public override Language TargetLanguage => Language.VisualBasic;
89 }
90
91 /// <summary>
92 /// Defines a Visual Basic based language constraint in debug mode.
93 /// </summary>
94 public class VisualBasicDebug : VisualBasic
95 {
96 /// <summary>
97 /// Gets resolution mode for <see cref="RazorEngine{TLanguage}"/> views - watching resolve path for debugging operations.
98 /// </summary>
99 public override RazorViewResolutionMode ResolutionMode => RazorViewResolutionMode.WatchingResolvePath;
100 }
101
102 /// <summary>
103 /// Defines a Visual Basic based language constraint for embedded resources.
104 /// </summary>
105 public class VisualBasicEmbeddedResource : VisualBasic
106 {
107 /// <summary>
108 /// Gets resolution mode for <see cref="RazorEngine{TLanguage}"/> views - embedded resources.
109 /// </summary>
110 public override RazorViewResolutionMode ResolutionMode => RazorViewResolutionMode.EmbeddedResource;
111 }
112}
Source/Libraries/GSF.Web/Model/RazorEngine.cs+330−0
@@ -0,0 +1,330 @@
1//******************************************************************************************************
2// RazorEngine.cs - Gbtc
3//
4// Copyright © 2016, Grid Protection Alliance. All Rights Reserved.
5//
6// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this
9// file except in compliance with the License. You may obtain a copy of the License at:
10//
11// http://opensource.org/licenses/MIT
12//
13// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15// License for the specific language governing permissions and limitations.
16//
17// Code Modification History:
18// ----------------------------------------------------------------------------------------------------
19// 05/05/2016 - J. Ritchie Carroll
20// Generated original version of source code.
21//
22//******************************************************************************************************
23
24using System;
25using System.Collections.Concurrent;
26using System.IO;
27using System.Linq;
28using System.Reflection;
29using System.Threading.Tasks;
30using System.Web.Hosting;
31using GSF.Configuration;
32using GSF.IO;
33using RazorEngine;
34using RazorEngine.Configuration;
35using RazorEngine.Templating;
36
37namespace GSF.Web.Model
38{
39 /// <summary>
40 /// Defines a Razor engine instance for the specified <typeparamref name="TLanguage"/> constraint.
41 /// </summary>
42 /// <typeparam name="TLanguage"><see cref="LanguageConstraint"/> for the Razor engine.</typeparam>
43 public class RazorEngine<TLanguage> : IRazorEngine where TLanguage : LanguageConstraint, new()
44 {
45 #region [ Members ]
46
47 // Fields
48 private readonly IRazorEngineService m_engineService;
49 private bool m_disposed;
50
51 #endregion
52
53 #region [ Constructors ]
54
55 /// <summary>
56 /// Creates a new <see cref="RazorEngine{TLanguage}"/> instance.
57 /// </summary>
58 /// <param name="templatePath">Template path for view files, if applicable.</param>
59 public RazorEngine(string templatePath)
60 {
61 if (string.IsNullOrEmpty(templatePath))
62 throw new ArgumentNullException(nameof(templatePath));
63
64 TLanguage languageType = new TLanguage();
65
66 switch (languageType.ResolutionMode)
67 {
68 case RazorViewResolutionMode.ResolvePath:
69 case RazorViewResolutionMode.WatchingResolvePath:
70 if (!Directory.Exists(templatePath))
71 throw new DirectoryNotFoundException();
72
73 if (languageType.ResolutionMode == RazorViewResolutionMode.ResolvePath)
74 {
75 m_engineService = RazorEngineService.Create(new TemplateServiceConfiguration
76 {
77 Language = languageType.TargetLanguage,
78 TemplateManager = new ResolvePathTemplateManager(new[] { templatePath }),
79 Debug = false
80 });
81 }
82 else
83 {
84 // The watching resolve path template manager should not be used in production since
85 // assemblies cannot be unloaded from an AppDomain. Every time a change to a .cshtml
86 // file is picked up by the watcher it is compiled and loaded into the AppDomain and
87 // the old one cannot be removed (.NET restriction), the net result is a memory leak
88 InvalidatingCachingProvider cachingProvider = new InvalidatingCachingProvider();
89
90 m_engineService = RazorEngineService.Create(new TemplateServiceConfiguration
91 {
92 Language = languageType.TargetLanguage,
93 CachingProvider = cachingProvider,
94 TemplateManager = new WatchingResolvePathTemplateManager(new[] { templatePath }, cachingProvider),
95 Debug = true
96 });
97 }
98 break;
99 case RazorViewResolutionMode.EmbeddedResource:
100 m_engineService = RazorEngineService.Create(new TemplateServiceConfiguration
101 {
102 Language = languageType.TargetLanguage,
103 TemplateManager = new DelegateTemplateManager(name =>
104 {
105 string resourceName = name;
106
107 if (!resourceName.Contains("."))
108 resourceName = templatePath + name;
109
110 Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
111
112 if ((object)stream == null)
113 return "";
114
115 using (StreamReader reader = new StreamReader(stream))
116 return reader.ReadToEnd();
117 }),
118 Debug = false
119 });
120 break;
121 }
122
123 TemplatePath = templatePath;
124 }
125
126 #endregion
127
128 #region [ Properties ]
129
130 /// <summary>
131 /// Gets the template path defined for this <see cref="RazorEngine{TLanguage}"/>.
132 /// </summary>
133 public string TemplatePath
134 {
135 get;
136 }
137
138 #endregion
139
140 #region [ Methods ]
141
142 /// <summary>
143 /// Releases all the resources used by the <see cref="RazorEngine{TLanguage}"/> object.
144 /// </summary>
145 public void Dispose()
146 {
147 Dispose(true);
148 GC.SuppressFinalize(this);
149 }
150
151 /// <summary>
152 /// Releases the unmanaged resources used by the <see cref="RazorEngine{TLanguage}"/> object and optionally releases the managed resources.
153 /// </summary>
154 /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
155 protected virtual void Dispose(bool disposing)
156 {
157 if (!m_disposed)
158 {
159 try
160 {
161 if (disposing)
162 m_engineService?.Dispose();
163 }
164 finally
165 {
166 m_disposed = true; // Prevent duplicate dispose.
167 }
168 }
169 }
170
171 /// <summary>
172 /// Gets a given key from the <see cref="ITemplateManager" /> implementation. See <see cref="ITemplateManager.GetKey(String,ResolveType,ITemplateKey)" />.
173 /// </summary>
174 /// <returns></returns>
175 public ITemplateKey GetKey(string name, ResolveType resolveType = ResolveType.Global, ITemplateKey context = null)
176 {
177 return m_engineService.GetKey(name, resolveType, context);
178 }
179
180 /// <summary>Checks if a given template is already cached.</summary>
181 /// <returns></returns>
182 public bool IsTemplateCached(ITemplateKey key, Type modelType)
183 {
184 return m_engineService.IsTemplateCached(key, modelType);
185 }
186
187 /// <summary>
188 /// Adds a given template to the template manager as dynamic template.
189 /// </summary>
190 public void AddTemplate(ITemplateKey key, ITemplateSource templateSource)
191 {
192 m_engineService.AddTemplate(key, templateSource);
193 }
194
195 /// <summary>Compiles the specified template and caches it.</summary>
196 public void Compile(ITemplateKey key, Type modelType = null)
197 {
198 m_engineService.Compile(key, modelType);
199 }
200
201 /// <summary>
202 /// Runs the given cached template. When the cache does not contain the template it will be compiled and cached beforehand.
203 /// </summary>
204 public void RunCompile(ITemplateKey key, TextWriter writer, Type modelType = null, object model = null, DynamicViewBag viewBag = null)
205 {
206 m_engineService.RunCompile(key, writer, modelType, model, viewBag);
207 }
208
209 /// <summary>Runs the given cached template.</summary>
210 public void Run(ITemplateKey key, TextWriter writer, Type modelType = null, object model = null, DynamicViewBag viewBag = null)
211 {
212 m_engineService.Run(key, writer, modelType, model, viewBag);
213 }
214
215 /// <summary>
216 /// Kicks off a task to pre-compile Razor templates.
217 /// </summary>
218 /// <param name="exceptionHandler">Exception handler used to report issues, if any.</param>
219 public Task PreCompile(Action<Exception> exceptionHandler = null)
220 {
221 return Task.Run(() =>
222 {
223 TLanguage languageType = new TLanguage();
224
225 if (languageType.ResolutionMode == RazorViewResolutionMode.EmbeddedResource)
226 {
227 foreach (string fileName in Assembly.GetExecutingAssembly().GetManifestResourceNames().Where(fileName => fileName.StartsWith(TemplatePath)))
228 {
229 try
230 {
231 m_engineService.Compile(fileName.Substring(TemplatePath.Length));
232 }
233 catch (Exception ex)
234 {
235 if ((object)exceptionHandler != null)
236 exceptionHandler(new InvalidOperationException($"Failed to pre-compile razor template \"{fileName}\": {ex.Message}", ex));
237 }
238 }
239 }
240 else
241 {
242 string webRootFolder = FilePath.AddPathSuffix(TemplatePath);
243 string[] razorFiles = FilePath.GetFileList($"{webRootFolder}*.{(languageType.TargetLanguage == Language.CSharp ? "cs" : "vb")}html");
244
245 foreach (string fileName in razorFiles)
246 {
247 try
248 {
249 m_engineService.Compile(FilePath.GetFileName(fileName));
250 }
251 catch (Exception ex)
252 {
253 if ((object)exceptionHandler != null)
254 exceptionHandler(new InvalidOperationException($"Failed to pre-compile razor template \"{fileName}\": {ex.Message}", ex));
255 }
256 }
257 }
258 });
259 }
260
261 #endregion
262
263 #region [ Static ]
264
265 // Static Fields
266 private static RazorEngine<TLanguage> s_defaultEngine;
267 private static readonly ConcurrentDictionary<string, RazorEngine<TLanguage>> s_configuredEngine;
268
269 // Static Properties
270
271 /// <summary>
272 /// Gets default configured razor engine instance.
273 /// </summary>
274 public static RazorEngine<TLanguage> Default => s_defaultEngine ?? (s_defaultEngine = GetConfiguredEngine());
275
276 // Static Constructor
277 static RazorEngine()
278 {
279 s_configuredEngine = new ConcurrentDictionary<string, RazorEngine<TLanguage>>(StringComparer.OrdinalIgnoreCase);
280 }
281
282 // Static Methods
283
284 /// <summary>
285 /// Gets a shared <see cref="RazorEngine{TLanguage}"/> instance created based on configured template path defined in the specified <paramref name="settingsCategory"/>.
286 /// </summary>
287 /// <param name="settingsCategory">Settings category to use for template path settings; defaults to "systemSettings".</param>
288 /// <returns>Shared <see cref="RazorEngine{TLanguage}"/> instance created based on configured template path.</returns>
289 public static RazorEngine<TLanguage> GetConfiguredEngine(string settingsCategory = null)
290 {
291 if (string.IsNullOrWhiteSpace(settingsCategory))
292 settingsCategory = "systemSettings";
293
294 return s_configuredEngine.GetOrAdd(settingsCategory, category =>
295 {
296 string templatePath = null;
297
298 // Get configured template path
299 CategorizedSettingsElementCollection systemSettings = ConfigurationFile.Current.Settings[category];
300
301 TLanguage languageType = new TLanguage();
302
303 switch (languageType.ResolutionMode)
304 {
305 case RazorViewResolutionMode.ResolvePath:
306 case RazorViewResolutionMode.WatchingResolvePath:
307 if (Common.GetApplicationType() == ApplicationType.Web)
308 {
309 systemSettings.Add("TemplatePath", "~/Views/Shared/Templates/", "Path for data context based razor field templates.");
310 templatePath = HostingEnvironment.MapPath(systemSettings["TemplatePath"].Value).EnsureEnd('/');
311 }
312 else
313 {
314 systemSettings.Add("TemplatePath", "wwwroot/Templates/", "Path for data context based razor field templates.");
315 templatePath = FilePath.GetAbsolutePath(systemSettings["TemplatePath"].Value);
316 }
317 break;
318 case RazorViewResolutionMode.EmbeddedResource:
319 systemSettings.Add("EmbeddedTemplatePath", "GSF.Web.Model.Views.", "Embedded name space path for data context based razor field templates.");
320 templatePath = systemSettings["EmbeddedTemplatePath"].Value.EnsureEnd('.');
321 break;
322 }
323
324 return new RazorEngine<TLanguage>(templatePath);
325 });
326 }
327
328 #endregion
329 }
330}
Source/Libraries/GSF.Web/Model/RazorView.cs+56−279
@@ -23,175 +23,59 @@ · 22 unmodified lines
23 23
24using System;24using System;
25using System.Collections.Generic;25using System.Collections.Generic;
26using System.IO;
27using System.Linq;
28using System.Net.Http;26using System.Net.Http;
29using System.Reflection;
30using System.Threading.Tasks;27using System.Threading.Tasks;
31using System.Web;28using System.Web;
32using System.Web.Hosting;
33using GSF.Collections;29using GSF.Collections;
34using GSF.Configuration;30using GSF.Data;
35using GSF.IO;
36using RazorEngine;
37using RazorEngine.Configuration;
38using RazorEngine.Templating;31using RazorEngine.Templating;
39 32
40// ReSharper disable StaticMemberInGenericType33// ReSharper disable StaticMemberInGenericType
41namespace GSF.Web.Model34namespace GSF.Web.Model
42{35{
43 /// <summary>
44 /// Defines resolutions modes for Razor view template files.
45 /// </summary>
46 public enum RazorViewResolutionMode
47 {
48 /// <summary>
49 /// Resolves template files from a path.
50 /// </summary>
51 ResolvePath,
52 /// <summary>
53 /// Resolves template files from a path and watches for changes.
54 /// </summary>
55 /// <remarks>
56 /// This should only be used in debug mode.
57 /// </remarks>
58 WatchingResolvePath,
59 /// <summary>
60 /// Resolves template files from an embedded resource.
61 /// </summary>
62 EmbeddedResource
63 }
64
65 /// <summary>
66 /// Defines a language constraint for a <see cref="RazorView{TLanguage}"/>.
67 /// </summary>
68 public abstract class LanguageConstraint
69 {
70 /// <summary>
71 /// Gets target language for the <see cref="LanguageConstraint"/> implementation.
72 /// </summary>
73 public abstract Language TargetLanguage
74 {
75 get;
76 }
77
78 /// <summary>
79 /// Gets resolution mode of <see cref="RazorView{TLanguage}"/>.
80 /// </summary>
81 public virtual RazorViewResolutionMode ResolutionMode => RazorViewResolutionMode.ResolvePath;
82 }
83
84 /// <summary>
85 /// Defines a C# based language constraint.
86 /// </summary>
87 public class CSharp : LanguageConstraint
88 {
89 /// <summary>
90 /// Gets target language for the <see cref="LanguageConstraint"/> implementation - C#.
91 /// </summary>
92 public override Language TargetLanguage => Language.CSharp;
93 }
94
95 /// <summary>
96 /// Defines a C# based language constraint in debug mode.
97 /// </summary>
98 public class CSharpDebug : CSharp
99 {
100 /// <summary>
101 /// Gets resolution mode of <see cref="RazorView{TLanguage}"/> - watching resolve path for debugging operations.
102 /// </summary>
103 public override RazorViewResolutionMode ResolutionMode => RazorViewResolutionMode.WatchingResolvePath;
104 }
105
106 /// <summary>
107 /// Defines a C# based language constraint for embedded resources.
108 /// </summary>
109 public class CSharpEmbeddedResource : CSharp
110 {
111 /// <summary>
112 /// Gets resolution mode of <see cref="RazorView{TLanguage}"/> - embedded resources.
113 /// </summary>
114 public override RazorViewResolutionMode ResolutionMode => RazorViewResolutionMode.EmbeddedResource;
115 }
116
117 /// <summary>
118 /// Defines a Visual Basic based language constraint.
119 /// </summary>
120 public class VisualBasic : LanguageConstraint
121 {
122 /// <summary>
123 /// Gets target language for the <see cref="LanguageConstraint"/> implementation - Visual Basic.
124 /// </summary>
125 public override Language TargetLanguage => Language.VisualBasic;
126 }
127
128 /// <summary>
129 /// Defines a Visual Basic based language constraint in debug mode.
130 /// </summary>
131 public class VisualBasicDebug : VisualBasic
132 {
133 /// <summary>
134 /// Gets resolution mode of <see cref="RazorView{TLanguage}"/> - watching resolve path for debugging operations.
135 /// </summary>
136 public override RazorViewResolutionMode ResolutionMode => RazorViewResolutionMode.WatchingResolvePath;
137 }
138
139 /// <summary>
140 /// Defines a Visual Basic based language constraint for embedded resources.
141 /// </summary>
142 public class VisualBasicEmbeddedResource : VisualBasic
143 {
144 /// <summary>
145 /// Gets resolution mode of <see cref="RazorView{TLanguage}"/> - embedded resources.
146 /// </summary>
147 public override RazorViewResolutionMode ResolutionMode => RazorViewResolutionMode.EmbeddedResource;
148 }
149
150 /// <summary>36 /// <summary>
151 /// Defines a view class for data context based Razor template implementations.37 /// Defines a view class for data context based Razor template implementations.
152 /// </summary>38 /// </summary>
153 /// <typeparam name="TLanguage"><see cref="LanguageConstraint"/> type to use for Razor views.</typeparam>39 public class RazorView
154 public class RazorView<TLanguage> : IRazorView where TLanguage : LanguageConstraint, new()
155 {40 {
156 #region [ Members ]41 #region [ Members ]
157 42
158 // Fields43 // Fields
44 private readonly IRazorEngine m_razorEngine;
45
159 private readonly DynamicViewBag m_viewBag = new DynamicViewBag();46 private readonly DynamicViewBag m_viewBag = new DynamicViewBag();
160 private Dictionary<string, string> m_parameters;47 private Dictionary<string, string> m_parameters;
161 48
162 #endregion49 #endregion
163 50
164 #region [ Constructors ]51 #region [ Constructors ]
165
166 /// <summary>
167 /// Creates a new <see cref="RazorView{TLanguage}"/>.
168 /// </summary>
169 public RazorView()
170 {
171 }
172
173 /// <summary>52 /// <summary>
174 /// Creates a new <see cref="RazorView{TLanguage}"/> with the specified exception handler.53 /// Creates a new <see cref="RazorView"/>.
175 /// </summary>54 /// </summary>
55 /// <param name="razorEngine"><see cref="IRazorEngine"/> instance to use.</param>
176 /// <param name="templateName">Name of template file, typically a .cshtml or .vbhtml file.</param>56 /// <param name="templateName">Name of template file, typically a .cshtml or .vbhtml file.</param>
177 /// <param name="exceptionHandler">Delegate to handle exceptions, if any.</param>57 /// <param name="exceptionHandler">Delegate to handle exceptions, if any.</param>
178 public RazorView(string templateName, Action<Exception> exceptionHandler = null)58 public RazorView(IRazorEngine razorEngine, string templateName, Action<Exception> exceptionHandler = null) : this(razorEngine, templateName, null, null, null, exceptionHandler)
179 {59 {
180 TemplateName = templateName;
181 ExceptionHandler = exceptionHandler;
182 }60 }
183 61
184 /// <summary>62 /// <summary>
185 /// Creates a new <see cref="RazorView{TLanguage}"/> with the specified parameters.63 /// Creates a new <see cref="RazorView"/>.
186 /// </summary>64 /// </summary>
65 /// <param name="razorEngine"><see cref="IRazorEngine"/> instance to use.</param>
187 /// <param name="templateName">Name of template file, typically a .cshtml or .vbhtml file.</param>66 /// <param name="templateName">Name of template file, typically a .cshtml or .vbhtml file.</param>
188 /// <param name="model">Reference to model to use when rendering template.</param>67 /// <param name="model">Reference to model to use when rendering template.</param>
189 /// <param name="modelType">Type of <paramref name="model"/>.</param>68 /// <param name="modelType">Type of <paramref name="model"/>.</param>
69 /// <param name="connection"><see cref="AdoDataConnection"/> to use, if any.</param>
190 /// <param name="exceptionHandler">Delegate to handle exceptions, if any.</param>70 /// <param name="exceptionHandler">Delegate to handle exceptions, if any.</param>
191 public RazorView(string templateName, object model, Type modelType, Action<Exception> exceptionHandler = null) : this(templateName, exceptionHandler)71 public RazorView(IRazorEngine razorEngine, string templateName, object model = null, Type modelType = null, AdoDataConnection connection = null, Action<Exception> exceptionHandler = null)
192 {72 {
73 m_razorEngine = razorEngine;
74 TemplateName = templateName;
193 Model = model;75 Model = model;
194 ModelType = modelType;76 ModelType = modelType;
77 Connection = connection;
78 ExceptionHandler = exceptionHandler;
195 }79 }
196 80
197 #endregion81 #endregion
@@ -222,14 +106,6 @@ namespace GSF.Web.Model · 24 unmodified lines
222 get; set;106 get; set;
223 }107 }
224 108
225 /// <summary>
226 /// Gets or sets delegate used to handle exceptions.
227 /// </summary>
228 public Action<Exception> ExceptionHandler
229 {
230 get; set;
231 }
232
233 /// <summary>109 /// <summary>
234 /// Gets reference to view bag used when rendering template.110 /// Gets reference to view bag used when rendering template.
235 /// </summary>111 /// </summary>
@@ -259,6 +135,43 @@ namespace GSF.Web.Model · 23 unmodified lines
259 }135 }
260 }136 }
261 137
138 /// <summary>
139 /// Gets reference to <see cref="IRazorEngine"/> used by this <see cref="RazorView"/>.
140 /// </summary>
141 public IRazorEngine RazorEngine => m_razorEngine;
142
143 /// <summary>
144 /// Gets or sets data connection to provide to <see cref="DataContext"/>, if any.
145 /// </summary>
146 public AdoDataConnection Connection
147 {
148 get;
149 set;
150 }
151
152 /// <summary>
153 /// Gets or sets delegate used to handle exceptions.
154 /// </summary>
155 public Action<Exception> ExceptionHandler
156 {
157 get; set;
158 }
159
160 /// <summary>
161 /// Gets or sets <see cref="IRazorEngine"/> to use for the <see cref="DataContext"/> provided to the view; defaults to <c>null</c>.
162 /// </summary>
163 /// <remarks>
164 /// This should typically not be changed. When value is <c>null</c>, the data context will use the default
165 /// <see cref="RazorEngine{TLanguage}"/> instance for <see cref="CSharpEmbeddedResource"/> which is used
166 /// to generate template based HTML input fields for a view. The default HTML input templates are defined
167 /// as embedded resources in GSF.Web.
168 /// </remarks>
169 public IRazorEngine DataContextRazorEngine
170 {
171 get;
172 set;
173 }
174
262 #endregion175 #endregion
263 176
264 #region [ Methods ]177 #region [ Methods ]
@@ -269,10 +182,10 @@ namespace GSF.Web.Model · 4 unmodified lines
269 /// <returns>Rendered result.</returns>182 /// <returns>Rendered result.</returns>
270 public string Execute()183 public string Execute()
271 {184 {
272 using (DataContext<TLanguage> dataContext = new DataContext<TLanguage>(exceptionHandler: ExceptionHandler))185 using (DataContext dataContext = new DataContext(Connection, razorEngine: DataContextRazorEngine, exceptionHandler: ExceptionHandler))
273 {186 {
274 m_viewBag.AddValue("DataContext", dataContext);187 m_viewBag.AddValue("DataContext", dataContext);
275 return s_engineService.RunCompile(TemplateName, ModelType, Model, m_viewBag);188 return m_razorEngine.RunCompile(TemplateName, ModelType, Model, m_viewBag);
276 }189 }
277 }190 }
278 191
@@ -282,7 +195,7 @@ namespace GSF.Web.Model · 3 unmodified lines
282 /// <returns>Rendered result.</returns>195 /// <returns>Rendered result.</returns>
283 public string Execute(HttpRequestMessage requestMessage, dynamic postData)196 public string Execute(HttpRequestMessage requestMessage, dynamic postData)
284 {197 {
285 using (DataContext<TLanguage> dataContext = new DataContext<TLanguage>(exceptionHandler: ExceptionHandler))198 using (DataContext dataContext = new DataContext(Connection, razorEngine: DataContextRazorEngine, exceptionHandler: ExceptionHandler))
286 {199 {
287 m_viewBag.AddValue("DataContext", dataContext);200 m_viewBag.AddValue("DataContext", dataContext);
288 m_viewBag.AddValue("Request", requestMessage);201 m_viewBag.AddValue("Request", requestMessage);
@@ -297,7 +210,7 @@ namespace GSF.Web.Model · 8 unmodified lines
297 m_viewBag.AddValue("PostData", postData);210 m_viewBag.AddValue("PostData", postData);
298 }211 }
299 212
300 return s_engineService.RunCompile(TemplateName, ModelType, Model, m_viewBag);213 return m_razorEngine.RunCompile(TemplateName, ModelType, Model, m_viewBag);
301 }214 }
302 }215 }
303 216
@@ -311,141 +224,5 @@ namespace GSF.Web.Model · 7 unmodified lines
311 }224 }
312 225
313 #endregion226 #endregion
314
315 #region [ Static ]
316
317 // Static Fields
318 private static readonly IRazorEngineService s_engineService;
319
320 /// <summary>
321 /// Defines default settings path for template files.
322 /// </summary>
323 public static readonly string TemplatePath;
324
325 // Static Constructor
326 static RazorView()
327 {
328 // The current thinking for this class is that there will only be one set of Razor views per application instance
329 TLanguage languageType = new TLanguage();
330
331 // Get configured template path
332 CategorizedSettingsElementCollection systemSettings = ConfigurationFile.Current.Settings["systemSettings"];
333
334 switch (languageType.ResolutionMode)
335 {
336 case RazorViewResolutionMode.ResolvePath:
337 case RazorViewResolutionMode.WatchingResolvePath:
338 if (Common.GetApplicationType() == ApplicationType.Web)
339 {
340 systemSettings.Add("TemplatePath", "~/Views/Shared/Templates/", "Path for data context based razor field templates.");
341 TemplatePath = HostingEnvironment.MapPath(systemSettings["TemplatePath"].Value).EnsureEnd('/');
342 }
343 else
344 {
345 systemSettings.Add("TemplatePath", "wwwroot/Templates/", "Path for data context based razor field templates.");
346 TemplatePath = FilePath.GetAbsolutePath(systemSettings["TemplatePath"].Value);
347 }
348
349 if (languageType.ResolutionMode == RazorViewResolutionMode.ResolvePath)
350 {
351 s_engineService = RazorEngineService.Create(new TemplateServiceConfiguration
352 {
353 Language = languageType.TargetLanguage,
354 TemplateManager = new ResolvePathTemplateManager(new[] { TemplatePath }),
355 Debug = false
356 });
357 }
358 else
359 {
360 // The watching resolve path template manager should not be used in production since
361 // assemblies cannot be unloaded from an AppDomain. Every time a change to a .cshtml
362 // file is picked up by the watcher it is compiled and loaded into the AppDomain and
363 // the old one cannot be removed (.NET restriction), the net result is a memory leak
364 InvalidatingCachingProvider cachingProvider = new InvalidatingCachingProvider();
365
366 s_engineService = RazorEngineService.Create(new TemplateServiceConfiguration
367 {
368 Language = languageType.TargetLanguage,
369 CachingProvider = cachingProvider,
370 TemplateManager = new WatchingResolvePathTemplateManager(new[] { TemplatePath }, cachingProvider),
371 Debug = true
372 });
373 }
374 break;
375 case RazorViewResolutionMode.EmbeddedResource:
376 systemSettings.Add("EmbeddedTemplatePath", "GSF.Web.Model.Views.", "Embedded name space path for data context based razor field templates.");
377 TemplatePath = systemSettings["EmbeddedTemplatePath"].Value.EnsureEnd('.');
378
379 s_engineService = RazorEngineService.Create(new TemplateServiceConfiguration
380 {
381 Language = languageType.TargetLanguage,
382 TemplateManager = new DelegateTemplateManager(name =>
383 {
384 string resourceName = name;
385
386 if (!resourceName.Contains("."))
387 resourceName = TemplatePath + name;
388
389 Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
390
391 if ((object)stream == null)
392 return "";
393
394 using (StreamReader reader = new StreamReader(stream))
395 return reader.ReadToEnd();
396 }),
397 Debug = false
398 });
399 break;
400 }
401 }
402
403 /// <summary>
404 /// Kicks off a task to pre-compile Razor templates.
405 /// </summary>
406 /// <param name="exceptionHandler">Exception handler used to report issues, if any.</param>
407 public static Task PreCompile(Action<Exception> exceptionHandler = null)
408 {
409 return Task.Run(() =>
410 {
411 TLanguage languageType = new TLanguage();
412
413 if (languageType.ResolutionMode == RazorViewResolutionMode.EmbeddedResource)
414 {
415 foreach (string fileName in Assembly.GetExecutingAssembly().GetManifestResourceNames().Where(fileName => fileName.StartsWith(TemplatePath)))
416 {
417 try
418 {
419 s_engineService.Compile(fileName.Substring(TemplatePath.Length));
420 }
421 catch (Exception ex)
422 {
423 if ((object)exceptionHandler != null)
424 exceptionHandler(new InvalidOperationException($"Failed to pre-compile razor template \"{fileName}\": {ex.Message}", ex));
425 }
426 }
427 }
428 else
429 {
430 string webRootFolder = FilePath.AddPathSuffix(TemplatePath);
431 string[] razorFiles = FilePath.GetFileList($"{webRootFolder}*.{(languageType.TargetLanguage == Language.CSharp ? "cs" : "vb")}html");
432
433 foreach (string fileName in razorFiles)
434 {
435 try
436 {
437 s_engineService.Compile(FilePath.GetFileName(fileName));
438 }
439 catch (Exception ex)
440 {
441 if ((object)exceptionHandler != null)
442 exceptionHandler(new InvalidOperationException($"Failed to pre-compile razor template \"{fileName}\": {ex.Message}", ex));
443 }
444 }
445 }
446 });
447 }
448
449 #endregion
450 }227 }
451}228}
Source/Libraries/GSF.Web/Model/RazorViewResolutionMode.cs+47−0
@@ -0,0 +1,47 @@
1//******************************************************************************************************
2// RazorViewResolutionMode.cs - Gbtc
3//
4// Copyright � 2016, Grid Protection Alliance. All Rights Reserved.
5//
6// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this
9// file except in compliance with the License. You may obtain a copy of the License at:
10//
11// http://opensource.org/licenses/MIT
12//
13// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15// License for the specific language governing permissions and limitations.
16//
17// Code Modification History:
18// ----------------------------------------------------------------------------------------------------
19// 05/05/2016 - J. Ritchie Carroll
20// Generated original version of source code.
21//
22//******************************************************************************************************
23
24namespace GSF.Web.Model
25{
26 /// <summary>
27 /// Defines resolutions modes for Razor view template files.
28 /// </summary>
29 public enum RazorViewResolutionMode
30 {
31 /// <summary>
32 /// Resolves template files from a path.
33 /// </summary>
34 ResolvePath,
35 /// <summary>
36 /// Resolves template files from a path and watches for changes.
37 /// </summary>
38 /// <remarks>
39 /// This should only be used in debug mode.
40 /// </remarks>
41 WatchingResolvePath,
42 /// <summary>
43 /// Resolves template files from an embedded resource.
44 /// </summary>
45 EmbeddedResource
46 }
47}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t