1 // Copyright 2004-2007 Castle Project - http://www.castleproject.org/
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle
.MonoRail
.Framework
18 using System
.Collections
.Generic
;
19 using System
.Configuration
;
22 using Castle
.Core
.Logging
;
25 /// Abstract base class for View Engines.
27 public abstract class ViewEngineBase
: IViewEngine
, IServiceEnabledComponent
29 private bool xhtmlRendering
;
30 private IViewSourceLoader viewSourceLoader
;
31 private ILogger logger
= NullLogger
.Instance
;
34 /// The service provider instance
36 protected IServiceProvider serviceProvider
;
38 #region IServiceEnabledComponent implementation
41 /// Services the specified provider.
43 /// <param name="provider">The provider.</param>
44 public virtual void Service(IServiceProvider provider
)
46 serviceProvider
= provider
;
48 viewSourceLoader
= (IViewSourceLoader
) provider
.GetService(typeof(IViewSourceLoader
));
50 if (viewSourceLoader
== null)
52 string message
= "Could not obtain IViewSourceLoader";
53 throw new ConfigurationErrorsException(message
);
56 ILoggerFactory loggerFactory
= (ILoggerFactory
) provider
.GetService(typeof(ILoggerFactory
));
58 if (loggerFactory
!= null)
60 logger
= loggerFactory
.Create(GetType());
66 #region IViewEngine implementation
69 /// Gets the view file extension.
71 /// <value>The view file extension.</value>
72 public abstract string ViewFileExtension { get; }
75 /// Gets a value indicating whether the view engine
76 /// support the generation of JS.
79 /// <c>true</c> if JS generation is supported; otherwise, <c>false</c>.
81 public abstract bool SupportsJSGeneration { get; }
84 /// Gets the JS generator file extension.
86 /// <value>The JS generator file extension.</value>
87 public abstract string JSGeneratorFileExtension { get; }
90 /// Implementors should return a generator instance if
91 /// the view engine supports JS generation.
93 /// <param name="generatorInfo">The generator info.</param>
94 /// <param name="context">The request context.</param>
95 /// <param name="controller">The controller.</param>
96 /// <param name="controllerContext">The controller context.</param>
97 /// <returns>A JS generator instance</returns>
98 public abstract object CreateJSGenerator(JSCodeGeneratorInfo generatorInfo
, IEngineContext context
, IController controller
,
99 IControllerContext controllerContext
);
102 /// Processes the js generation view template - using the templateName
103 /// to obtain the correct template, and using the specified <see cref="TextWriter"/>
104 /// to output the result.
106 /// <param name="templateName">Name of the template.</param>
107 /// <param name="output">The output.</param>
108 /// <param name="generatorInfo">The generator info.</param>
109 /// <param name="context">The request context.</param>
110 /// <param name="controller">The controller.</param>
111 /// <param name="controllerContext">The controller context.</param>
112 public abstract void GenerateJS(string templateName
, TextWriter output
, JSCodeGeneratorInfo generatorInfo
,
113 IEngineContext context
, IController controller
, IControllerContext controllerContext
);
116 /// Gets/sets whether rendering should aim
117 /// to be XHTML compliant, obtained from the configuration.
119 public bool XHtmlRendering
121 get { return xhtmlRendering; }
122 set { xhtmlRendering = value; }
126 /// Evaluates whether the specified template exists.
128 /// <returns><c>true</c> if it exists</returns>
129 public virtual bool HasTemplate(String templateName
)
132 ViewSourceLoader
.HasSource(ResolveTemplateName(templateName
)) ||
133 ViewSourceLoader
.HasSource(ResolveJSTemplateName(templateName
));
137 /// Evaluates whether the specified template exists.
139 /// <returns><c>true</c> if it exists</returns>
140 public virtual bool HasJsGenerationTemplate(String templateName
)
142 return ViewSourceLoader
.HasSource(templateName
);
146 /// Evaluates whether the specified template can be used to generate js.
148 /// <returns><c>true</c> if it exists and has the correct file extension</returns>
149 public virtual bool IsTemplateForJSGeneration(String templateName
)
151 string resolvedTemplateName
= ResolveJSTemplateName(templateName
);
154 string.Compare(Path
.GetExtension(resolvedTemplateName
), JSGeneratorFileExtension
, true) == 0 &&
155 HasJsGenerationTemplate(resolvedTemplateName
);
159 /// Processes the view - using the templateName
160 /// to obtain the correct template
161 /// and writes the results to the System.IO.TextWriter.
163 public abstract void Process(String templateName
, TextWriter output
, IEngineContext context
, IController controller
,
164 IControllerContext controllerContext
);
168 /// Processes the view - using the templateName
169 /// to obtain the correct template
170 /// and writes the results to the <see cref="TextWriter"/>.
172 public abstract void Process(string templateName
, string layoutName
, TextWriter output
,
173 IDictionary
<string, object> parameters
);
176 /// Should process the specified partial. The partial name must contains
177 /// the path relative to the views folder.
179 /// <param name="output">The output.</param>
180 /// <param name="context">The request context.</param>
181 /// <param name="controller">The controller.</param>
182 /// <param name="controllerContext">The controller context.</param>
183 /// <param name="partialName">The partial name.</param>
184 public abstract void ProcessPartial(string partialName
, TextWriter output
, IEngineContext context
,
185 IController controller
, IControllerContext controllerContext
);
188 /// Wraps the specified content in the layout using the
189 /// context to output the result.
191 public abstract void RenderStaticWithinLayout(String contents
, IEngineContext context
, IController controller
,
192 IControllerContext controllerContext
);
195 /// Resolves the template name into a file name with the proper file extension
197 protected virtual string ResolveTemplateName(string templateName
)
199 if (Path
.HasExtension(templateName
))
205 return templateName
+ ViewFileExtension
;
210 /// Resolves the template name into a JS generation file name with the proper file extension
212 protected virtual string ResolveJSTemplateName(string templateName
)
214 if (Path
.HasExtension(templateName
))
220 return templateName
+ JSGeneratorFileExtension
;
226 #region Pre/Post send view
229 /// Invokes the <see cref="IController.PreSendView"/>
231 /// <param name="controller">The controller.</param>
232 /// <param name="view">The view argument.</param>
233 protected virtual void PreSendView(IController controller
, object view
)
235 controller
.PreSendView(view
);
239 /// Invokes the <see cref="IController.PostSendView"/>
241 /// <param name="controller">The controller.</param>
242 /// <param name="view">The view argument.</param>
243 protected virtual void PostSendView(IController controller
, object view
)
245 controller
.PostSendView(view
);
250 #region Useful properties
253 /// Gets or sets the view source loader.
255 /// <value>The view source loader.</value>
256 protected IViewSourceLoader ViewSourceLoader
258 get { return viewSourceLoader; }
259 set { viewSourceLoader = value; }
265 /// <value>The logger.</value>
266 protected ILogger Logger
268 get { return logger; }
273 #region Render Helpers
276 /// Sets the HTTP Content-Type header appropriately.
278 protected virtual void AdjustContentType(IEngineContext context
)
282 //Find out what they'll accept
283 String httpAccept
= context
.Request
.AcceptHeader
;
285 //TODO: Evaluate the q-values of the Accept header
287 //Do they accept application/xhtml+xml?
288 if (httpAccept
!= null && httpAccept
.IndexOf("application/xhtml+xml") != -1)
290 //Send them the proper content type
291 context
.Response
.ContentType
= "application/xhtml+xml";
293 //TODO: Add the xml prolog for browsers that support it
294 //response.Write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
298 //Fall back to text/html for older folk
299 context
.Response
.ContentType
= "text/html";
303 context
.Response
.AppendHeader("Vary", "Accept");
305 else if (context
.Response
.ContentType
== null)
308 context
.Response
.ContentType
= "text/html";
313 /// Sets the HTTP Content-Type header to <c>text/javascript</c>
315 protected void AdjustJavascriptContentType(IEngineContext context
)
317 context
.Response
.ContentType
= "text/javascript";