Minor style changes
[castle.git] / MonoRail / Castle.MonoRail.Framework / Controller.cs
blob94ab35e97c37bb44224ed7ef73808a113deb33d0
1 // Copyright 2004-2007 Castle Project - http://www.castleproject.org/
2 //
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
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
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
17 using System;
18 using System.Collections.Generic;
19 using System.IO;
20 using System.Web;
21 using System.Reflection;
22 using System.Collections;
23 using System.Collections.Specialized;
25 using Castle.Components.Common.EmailSender;
26 using Castle.Components.Validator;
27 using Castle.Core.Logging;
28 using Castle.MonoRail.Framework.Configuration;
29 using Castle.MonoRail.Framework.Helpers;
30 using Castle.MonoRail.Framework.Internal;
32 /// <summary>
33 /// Implements the core functionality and exposes the
34 /// common methods for concrete controllers.
35 /// </summary>
36 public abstract class Controller : IController
38 #region Fields
40 /// <summary>
41 /// Holds the request/context information
42 /// </summary>
43 internal IRailsEngineContext context;
45 /// <summary>
46 /// The reference to the <see cref="IViewEngineManager"/> instance
47 /// </summary>
48 internal IViewEngineManager viewEngineManager;
50 /// <summary>
51 /// Logger instance. Should never be null
52 /// </summary>
53 internal ILogger logger = NullLogger.Instance;
55 /// <summary>
56 /// Holds information to pass to the view
57 /// </summary>
58 private IDictionary bag = new HybridDictionary();
60 /// <summary>
61 /// The area name which was used to access this controller
62 /// </summary>
63 private string _areaName;
65 /// <summary>
66 /// The controller name which was used to access this controller
67 /// </summary>
68 private string _controllerName;
70 /// <summary>
71 /// The view name selected to be rendered after the execution
72 /// of the action
73 /// </summary>
74 internal string _selectedViewName;
76 /// <summary>
77 /// The layout name that the view engine should use
78 /// </summary>
79 private string _layoutName;
81 /// <summary>
82 /// The original action requested
83 /// </summary>
84 private string _evaluatedAction;
86 /// <summary>
87 /// True if any Controller.Send operation was called.
88 /// </summary>
89 private bool _resetIsPostBack;
91 /// <summary>
92 /// The helper instances collected
93 /// </summary>
94 internal IDictionary helpers = null;
96 /// <summary>
97 /// The resources associated with this controller
98 /// </summary>
99 internal ResourceDictionary resources = null;
101 /// <summary>
102 /// Reference to the <see cref="IResourceFactory"/> instance
103 /// </summary>
104 // internal IResourceFactory resourceFactory;
105 internal IDictionary<string, IDynamicAction> _dynamicActions = new Dictionary<string, IDynamicAction>(StringComparer.InvariantCultureIgnoreCase);
107 internal bool directRenderInvoked;
109 internal ControllerMetaDescriptor metaDescriptor;
111 internal IServiceProvider serviceProvider;
113 internal ValidatorRunner validator;
115 #endregion
117 #region Constructors
119 /// <summary>
120 /// Constructs a Controller
121 /// </summary>
122 public Controller()
126 #endregion
128 #region Useful Properties
130 /// <summary>
131 /// Gets the view folder -- (areaname +
132 /// controllername) or just controller name -- that this controller
133 /// will use by default.
134 /// </summary>
135 public string ViewFolder
139 if (_areaName != null && _areaName.Length > 0)
141 return Path.Combine(_areaName, _controllerName);
144 return _controllerName;
148 /// <summary>
149 /// This is intended to be used by MonoRail infrastructure.
150 /// </summary>
151 public ControllerMetaDescriptor MetaDescriptor
153 get { return metaDescriptor; }
156 /// <summary>
157 /// Gets the actions available in this controller.
158 /// </summary>
159 /// <remarks>It is supposed to be used by MonoRail infrastructure only</remarks>
160 /// <value>The actions.</value>
161 public ICollection Actions
163 get { return metaDescriptor.Actions.Values; }
166 /// <summary>
167 /// Gets a dicitionary of name/<see cref="IResource"/>
168 /// </summary>
169 /// <remarks>It is supposed to be used by MonoRail infrastructure only</remarks>
170 /// <value>The resources.</value>
171 public ResourceDictionary Resources
173 get { return resources; }
176 /// <summary>
177 /// Gets a dictionary of name/helper instance
178 /// </summary>
179 /// <value>The helpers.</value>
180 public IDictionary Helpers
182 get { return helpers; }
185 /// <summary>
186 /// Gets a value indicating whether the request is a post.
187 /// </summary>
188 /// <value>
189 /// <see langword="true"/> if this request is a post; otherwise, <see langword="false"/>.
190 /// </value>
191 public bool IsPost
193 get { return context.Request.HttpMethod == "POST"; }
196 /// <summary>
197 /// Gets a value indicating whether the request is a get.
198 /// </summary>
199 /// <value>
200 /// <see langword="true"/> if this request is a get; otherwise, <see langword="false"/>.
201 /// </value>
202 public bool IsGet
204 get { return context.Request.HttpMethod == "GET"; }
207 /// <summary>
208 /// Gets a value indicating whether the request is a put.
209 /// </summary>
210 /// <value>
211 /// <see langword="true"/> if this request is a put; otherwise, <see langword="false"/>.
212 /// </value>
213 public bool IsPut
215 get { return context.Request.HttpMethod == "PUT"; }
218 /// <summary>
219 /// Gets a value indicating whether the request is a head.
220 /// </summary>
221 /// <value>
222 /// <see langword="true"/> if this request is a head; otherwise, <see langword="false"/>.
223 /// </value>
224 public bool IsHead
226 get { return context.Request.HttpMethod == "HEAD"; }
229 /// <summary>
230 /// Gets the controller's name.
231 /// </summary>
232 public string Name
234 get { return _controllerName; }
237 /// <summary>
238 /// Gets the controller's area name.
239 /// </summary>
240 public string AreaName
242 get { return _areaName; }
245 /// <summary>
246 /// Gets or set the layout being used.
247 /// </summary>
248 public string LayoutName
250 get { return _layoutName; }
251 set { _layoutName = value; }
254 /// <summary>
255 /// Gets the name of the action being processed.
256 /// </summary>
257 public string Action
259 get { return _evaluatedAction; }
262 /// <summary>
263 /// Logger for the controller
264 /// </summary>
265 public ILogger Logger
267 get { return logger; }
268 set { logger = value; }
271 /// <summary>
272 /// Gets or sets the view which will be rendered by this action.
273 /// </summary>
274 public string SelectedViewName
276 get { return _selectedViewName; }
277 set { _selectedViewName = value; }
280 /// <summary>
281 /// Gets the property bag, which is used
282 /// to pass variables to the view.
283 /// </summary>
284 public IDictionary PropertyBag
286 get { return bag; }
287 set { bag = value; }
290 /// <summary>
291 /// Gets the context of this request execution.
292 /// </summary>
293 public IRailsEngineContext Context
295 get { return context; }
298 /// <summary>
299 /// Gets the Session dictionary.
300 /// </summary>
301 protected IDictionary Session
303 get { return context.Session; }
306 /// <summary>
307 /// Gets a dictionary of volative items.
308 /// Ideal for showing success and failures messages.
309 /// </summary>
310 public Flash Flash
312 get { return context.Flash; }
315 /// <summary>
316 /// Gets the web context of ASP.NET API.
317 /// </summary>
318 protected internal HttpContext HttpContext
320 get { return context.UnderlyingContext; }
323 /// <summary>
324 /// Gets the request object.
325 /// </summary>
326 public IRequest Request
328 get { return Context.Request; }
331 /// <summary>
332 /// Gets the response object.
333 /// </summary>
334 public IResponse Response
336 get { return Context.Response; }
339 /// <summary>
340 /// Shortcut to <see cref="IRequest.Params"/>
341 /// </summary>
342 public NameValueCollection Params
344 get { return Request.Params; }
347 /// <summary>
348 /// Shortcut to <see cref="IRequest.Form"/>
349 /// </summary>
350 public NameValueCollection Form
352 get { return Request.Form; }
355 /// <summary>
356 /// Shortcut to <see cref="IRequest.QueryString"></see>
357 /// </summary>
358 public NameValueCollection Query
360 get { return Request.QueryString; }
363 /// <summary>
364 /// Gets the dynamic actions dictionary.
365 /// <para>
366 /// Can be used to insert dynamic actions on the controller instance.
367 /// </para>
368 /// </summary>
369 /// <value>The dynamic actions dictionary.</value>
370 public IDictionary<string, IDynamicAction> DynamicActions
372 get { return _dynamicActions; }
375 /// <summary>
376 /// Gets the validator runner instance.
377 /// </summary>
378 /// <value>The validator instance.</value>
379 public ValidatorRunner Validator
381 get { return validator; }
382 set { validator = value; }
385 /// <summary>
386 /// Gets the URL builder instance.
387 /// </summary>
388 /// <value>The URL builder.</value>
389 public IUrlBuilder UrlBuilder
391 get { return (IUrlBuilder) serviceProvider.GetService(typeof(IUrlBuilder)); }
394 /// <summary>
395 /// Shortcut to
396 /// <see cref="IResponse.IsClientConnected"/>
397 /// </summary>
398 protected bool IsClientConnected
400 get { return context.Response.IsClientConnected; }
403 /// <summary>
404 /// Indicates that the current Action resulted from an ASP.NET PostBack.
405 /// As a result, this property is only relavent to controllers using
406 /// WebForms views. It is placed on the base Controller for convenience
407 /// only to avoid the need to extend the Controller or provide additional
408 /// helper classes. It is marked virtual to better support testing.
409 /// </summary>
410 protected virtual bool IsPostBack
414 if (_resetIsPostBack) return false;
416 NameValueCollection fields = Context.Params;
417 return (fields["__VIEWSTATE"] != null) || (fields["__EVENTTARGET"] != null);
421 #endregion
423 #region Useful Operations
425 /// <summary>
426 /// Specifies the view to be processed after the action has finished its processing.
427 /// </summary>
428 /// <param name="name">view template name (the file extension is optional)</param>
429 public void RenderView(string name)
431 _selectedViewName = Path.Combine(ViewFolder, name);
434 /// <summary>
435 /// Specifies the view to be processed after the action has finished its processing.
436 /// </summary>
437 /// <param name="name">view template name (the file extension is optional)</param>
438 /// <param name="skipLayout">If set to <c>true</c>, no layout will be used when rendering the view</param>
439 public void RenderView(string name, bool skipLayout)
441 if (skipLayout) CancelLayout();
443 RenderView(name);
446 /// <summary>
447 /// Specifies the view to be processed after the action has finished its processing.
448 /// </summary>
449 /// <param name="name">view template name (the file extension is optional)</param>
450 /// <param name="skipLayout">If set to <c>true</c>, no layout will be used when rendering the view</param>
451 /// <param name="mimeType">The mime type to use on the reply</param>
452 public void RenderView(string name, bool skipLayout, string mimeType)
454 if (skipLayout) CancelLayout();
455 Response.ContentType = mimeType;
457 RenderView(name);
460 /// <summary>
461 /// Specifies the view to be processed after the action has finished its processing.
462 /// </summary>
463 /// <param name="controller">Controller name get view from (if you intend to user another controller's view</param>
464 /// <param name="name">view template name (the file extension is optional)</param>
465 public void RenderView(string controller, string name)
467 _selectedViewName = Path.Combine(controller, name);
470 /// <summary>
471 /// Specifies the view to be processed after the action has finished its processing.
472 /// </summary>
473 /// <param name="controller">Controller name get view from (if you intend to user another controller's view</param>
474 /// <param name="name">view template name (the file extension is optional)</param>
475 /// <param name="skipLayout">If set to <c>true</c>, no layout will be used when rendering the view</param>
476 public void RenderView(string controller, string name, bool skipLayout)
478 if (skipLayout) CancelLayout();
480 RenderView(controller, name);
483 /// <summary>
484 /// Specifies the view to be processed after the action has finished its processing.
485 /// </summary>
486 /// <param name="controller">Controller name get view from (if you intend to user another controller's view</param>
487 /// <param name="name">view template name (the file extension is optional)</param>
488 /// <param name="skipLayout">If set to <c>true</c>, no layout will be used when rendering the view</param>
489 /// <param name="mimeType">The mime type to use on the reply</param>
490 public void RenderView(string controller, string name, bool skipLayout, string mimeType)
492 if (skipLayout) CancelLayout();
493 Response.ContentType = mimeType;
495 RenderView(controller, name);
498 /// <summary>
499 /// Specifies the view to be processed after the action has finished its processing.
500 /// </summary>
501 /// <param name="controller">Controller name get view from (if you intend to user another controller's view</param>
502 /// <param name="name">view template name (the file extension is optional)</param>
503 /// <param name="mimeType">The mime type to use on the reply</param>
504 public void RenderView(string controller, string name, string mimeType)
506 Response.ContentType = mimeType;
508 RenderView(controller, name);
511 /// <summary>
512 /// Specifies the view to be processed and results are written to System.IO.TextWriter.
513 /// </summary>
514 /// <param name="output"></param>
515 /// <param name="name">The name of the view to process.</param>
516 public void InPlaceRenderView(TextWriter output, string name)
518 viewEngineManager.Process(output, Context, this, Path.Combine(ViewFolder, name));
521 /// <summary>
522 /// Specifies the shared view to be processed after the action has finished its
523 /// processing. (A partial view shared
524 /// by others views and usually in the root folder
525 /// of the view directory).
526 /// </summary>
527 public void RenderSharedView(string name)
529 _selectedViewName = name;
532 /// <summary>
533 /// Specifies the shared view to be processed after the action has finished its
534 /// processing. (A partial view shared
535 /// by others views and usually in the root folder
536 /// of the view directory).
537 /// </summary>
538 public void RenderSharedView(string name, bool skipLayout)
540 if (skipLayout) CancelLayout();
542 RenderSharedView(name);
545 /// <summary>
546 /// Specifies the shared view to be processed and results are written to System.IO.TextWriter.
547 /// (A partial view shared by others views and usually in the root folder
548 /// of the view directory).
549 /// </summary>
550 /// <param name="output"></param>
551 /// <param name="name">The name of the view to process.</param>
552 public void InPlaceRenderSharedView(TextWriter output, string name)
554 viewEngineManager.Process(output, Context, this, name);
557 /// <summary>
558 /// Cancels the view processing.
559 /// </summary>
560 public void CancelView()
562 _selectedViewName = null;
565 /// <summary>
566 /// Cancels the layout processing.
567 /// </summary>
568 public void CancelLayout()
570 LayoutName = null;
573 /// <summary>
574 /// Cancels the view processing and writes
575 /// the specified contents to the browser
576 /// </summary>
577 public void RenderText(string contents)
579 CancelView();
581 Response.Write(contents);
584 /// <summary>
585 /// Cancels the view processing and writes
586 /// the specified contents to the browser
587 /// </summary>
588 public void RenderText(string contents, params object[] args)
590 RenderText(String.Format(contents, args));
593 /// <summary>
594 /// Cancels the view processing and writes
595 /// the specified contents to the browser
596 /// </summary>
597 public void RenderText(IFormatProvider formatProvider, string contents, params object[] args)
599 RenderText(String.Format(formatProvider, contents, args));
602 /// <summary>
603 /// Sends raw contents to be rendered directly by the view engine.
604 /// It's up to the view engine just to apply the layout and nothing else.
605 /// </summary>
606 /// <param name="contents">Contents to be rendered.</param>
607 public void DirectRender(string contents)
609 CancelView();
611 if (directRenderInvoked)
613 throw new ControllerException("DirectRender should be called only once.");
616 directRenderInvoked = true;
618 viewEngineManager.ProcessContents(context, this, contents);
621 /// <summary>
622 /// Returns true if the specified template exists.
623 /// </summary>
624 /// <param name="templateName"></param>
625 public bool HasTemplate(string templateName)
627 return viewEngineManager.HasTemplate(templateName);
630 #region RedirectToRoute
632 /// <summary>
633 /// Pendent.
634 /// </summary>
635 /// <param name="routeName">Name of the route.</param>
636 public void RedirectToRoute(string routeName)
638 Redirect(UrlBuilder.BuildRouteUrl(Context.UrlInfo, routeName));
641 /// <summary>
642 /// Pendent.
643 /// </summary>
644 /// <param name="routeName">Name of the route.</param>
645 /// <param name="parameters">The parameters.</param>
646 public void RedirectToRoute(string routeName, IDictionary parameters)
648 Redirect(UrlBuilder.BuildRouteUrl(Context.UrlInfo, routeName, parameters));
651 /// <summary>
652 /// Pendent.
653 /// </summary>
654 /// <param name="routeName">Name of the route.</param>
655 /// <param name="parameters">The parameters.</param>
656 public void RedirectToRoute(string routeName, object parameters)
658 Redirect(UrlBuilder.BuildRouteUrl(Context.UrlInfo, routeName, parameters));
661 #endregion
663 #region RedirectToAction
665 /// <summary>
666 /// Redirects to another action in the same controller.
667 /// </summary>
668 /// <param name="action">The action name</param>
669 protected void RedirectToAction(string action)
671 RedirectToAction(action, (NameValueCollection) null);
674 /// <summary>
675 /// Redirects to another action in the same controller.
676 /// </summary>
677 /// <param name="action">The action name</param>
678 /// <param name="queryStringParameters">list of key/value pairs. Each string is supposed
679 /// to have the format "key=value" that will be converted to a proper
680 /// query string</param>
681 protected void RedirectToAction(string action, params String[] queryStringParameters)
683 RedirectToAction(action, DictHelper.Create(queryStringParameters));
686 /// <summary>
687 /// Redirects to another action in the same controller.
688 /// </summary>
689 /// <param name="action">The action name</param>
690 /// <param name="queryStringParameters">Query string entries</param>
691 protected void RedirectToAction(string action, IDictionary queryStringParameters)
693 if (queryStringParameters != null)
695 Redirect(AreaName, Name, TransformActionName(action), queryStringParameters);
697 else
699 Redirect(AreaName, Name, TransformActionName(action));
703 /// <summary>
704 /// Redirects to another action in the same controller.
705 /// </summary>
706 /// <param name="action">The action name</param>
707 /// <param name="queryStringParameters">Query string entries</param>
708 protected void RedirectToAction(string action, NameValueCollection queryStringParameters)
710 if (queryStringParameters != null)
712 Redirect(AreaName, Name, TransformActionName(action), queryStringParameters);
714 else
716 Redirect(AreaName, Name, TransformActionName(action));
720 #endregion
722 /// <summary>
723 /// Redirects to the referrer action, according to the "HTTP_REFERER" header (<c>Context.UrlReferrer</c>).
724 /// </summary>
725 [Obsolete("Use RedirectToReferrer")]
726 protected void RedirectToReferer()
728 RedirectToReferrer();
731 /// <summary>
732 /// Redirects to the referrer action, according to the "HTTP_REFERER" header (<c>Context.UrlReferrer</c>).
733 /// </summary>
734 protected void RedirectToReferrer()
736 Redirect(Context.UrlReferrer);
739 /// <summary>
740 /// Redirects to the site root directory (<c>Context.ApplicationPath + "/"</c>).
741 /// </summary>
742 public void RedirectToSiteRoot()
744 Redirect(Context.ApplicationPath + "/");
747 /// <summary>
748 /// Redirects to the specified URL. All other Redirects call this one.
749 /// </summary>
750 /// <param name="url">Target URL</param>
751 public virtual void Redirect(string url)
753 CancelView();
755 context.Response.Redirect(url);
758 /// <summary>
759 /// Redirects to the specified URL.
760 /// </summary>
761 /// <param name="url">Target URL</param>
762 /// <param name="parameters">URL parameters</param>
763 public virtual void Redirect(string url, IDictionary parameters)
765 if (parameters != null && parameters.Count != 0)
767 if (url.IndexOf('?') != -1)
769 url = url + '&' + ToQueryString(parameters);
771 else
773 url = url + '?' + ToQueryString(parameters);
777 Redirect(url);
780 /// <summary>
781 /// Redirects to the specified URL.
782 /// </summary>
783 /// <param name="url">Target URL</param>
784 /// <param name="parameters">URL parameters</param>
785 public virtual void Redirect(string url, NameValueCollection parameters)
787 if (parameters != null && parameters.Count != 0)
789 if (url.IndexOf('?') != -1)
791 url = url + '&' + ToQueryString(parameters);
793 else
795 url = url + '?' + ToQueryString(parameters);
799 Redirect(url);
802 /// <summary>
803 /// Redirects to another controller and action.
804 /// </summary>
805 /// <param name="controller">Controller name</param>
806 /// <param name="action">Action name</param>
807 public void Redirect(string controller, string action)
809 Redirect(UrlBuilder.BuildUrl(Context.UrlInfo, controller, action));
812 /// <summary>
813 /// Redirects to another controller and action.
814 /// </summary>
815 /// <param name="area">Area name</param>
816 /// <param name="controller">Controller name</param>
817 /// <param name="action">Action name</param>
818 public void Redirect(string area, string controller, string action)
820 Redirect(UrlBuilder.BuildUrl(Context.UrlInfo, area, controller, action));
823 /// <summary>
824 /// Redirects to another controller and action with the specified paramters.
825 /// </summary>
826 /// <param name="controller">Controller name</param>
827 /// <param name="action">Action name</param>
828 /// <param name="parameters">Key/value pairings</param>
829 public void Redirect(string controller, string action, NameValueCollection parameters)
831 Redirect(UrlBuilder.BuildUrl(Context.UrlInfo, controller, action, parameters));
834 /// <summary>
835 /// Redirects to another controller and action with the specified paramters.
836 /// </summary>
837 /// <param name="area">Area name</param>
838 /// <param name="controller">Controller name</param>
839 /// <param name="action">Action name</param>
840 /// <param name="parameters">Key/value pairings</param>
841 public void Redirect(string area, string controller, string action, NameValueCollection parameters)
843 Redirect(UrlBuilder.BuildUrl(Context.UrlInfo, area, controller, action, parameters));
846 /// <summary>
847 /// Redirects to another controller and action with the specified paramters.
848 /// </summary>
849 /// <param name="controller">Controller name</param>
850 /// <param name="action">Action name</param>
851 /// <param name="parameters">Key/value pairings</param>
852 public void Redirect(string controller, string action, IDictionary parameters)
854 Redirect(UrlBuilder.BuildUrl(Context.UrlInfo, controller, action, parameters));
857 /// <summary>
858 /// Redirects to another controller and action with the specified paramters.
859 /// </summary>
860 /// <param name="area">Area name</param>
861 /// <param name="controller">Controller name</param>
862 /// <param name="action">Action name</param>
863 /// <param name="parameters">Key/value pairings</param>
864 public void Redirect(string area, string controller, string action, IDictionary parameters)
866 Redirect(UrlBuilder.BuildUrl(Context.UrlInfo, area, controller, action, parameters));
869 /// <summary>
870 /// Creates a querystring string representation of the namevalue collection.
871 /// </summary>
872 /// <param name="parameters">The parameters.</param>
873 /// <returns></returns>
874 protected string ToQueryString(NameValueCollection parameters)
876 return CommonUtils.BuildQueryString(Context.Server, parameters, false);
879 /// <summary>
880 /// Creates a querystring string representation of the entries in the dictionary.
881 /// </summary>
882 /// <param name="parameters">The parameters.</param>
883 /// <returns></returns>
884 protected string ToQueryString(IDictionary parameters)
886 return CommonUtils.BuildQueryString(Context.Server, parameters, false);
889 #endregion
891 #region Core members
893 /// <summary>
894 /// Extracts the services the controller uses from the context -- which ultimately
895 /// is a service provider.
896 /// </summary>
897 /// <param name="context">The context/service provider.</param>
898 public void InitializeFieldsFromServiceProvider(IRailsEngineContext context)
900 serviceProvider = context;
902 viewEngineManager = (IViewEngineManager) serviceProvider.GetService(typeof(IViewEngineManager));
904 IControllerDescriptorProvider controllerDescriptorBuilder = (IControllerDescriptorProvider)
905 serviceProvider.GetService( typeof(IControllerDescriptorProvider) );
907 metaDescriptor = controllerDescriptorBuilder.BuildDescriptor(this);
909 ILoggerFactory loggerFactory = (ILoggerFactory) context.GetService(typeof(ILoggerFactory));
911 if (loggerFactory != null)
913 logger = loggerFactory.Create(GetType().Name);
916 this.context = context;
918 Initialize();
921 /// <summary>
922 /// Initializes the state of the controller.
923 /// </summary>
924 /// <param name="areaName">Name of the area.</param>
925 /// <param name="controllerName">Name of the controller.</param>
926 /// <param name="actionName">Name of the action.</param>
927 public void InitializeControllerState(string areaName, string controllerName, string actionName)
929 SetEvaluatedAction(actionName);
930 _areaName = areaName;
931 _controllerName = controllerName;
934 /// <summary>
935 /// Sets the evaluated action.
936 /// </summary>
937 /// <param name="actionName">Name of the action.</param>
938 internal void SetEvaluatedAction(string actionName)
940 _evaluatedAction = actionName;
943 /// <summary>
944 /// Gets the service provider.
945 /// </summary>
946 /// <value>The service provider.</value>
947 protected internal IServiceProvider ServiceProvider
949 get { return serviceProvider; }
952 /// <summary>
953 /// Performs the specified action, which means:
954 /// <br/>
955 /// 1. Define the default view name<br/>
956 /// 2. Run the before filters<br/>
957 /// 3. Select the method related to the action name and invoke it<br/>
958 /// 4. On error, execute the rescues if available<br/>
959 /// 5. Run the after filters<br/>
960 /// 6. Invoke the view engine<br/>
961 /// </summary>
962 /// <param name="action">Action name</param>
963 public void Send(string action)
965 ResetIsPostback();
966 InternalSend(action, null);
969 /// <summary>
970 /// Performs the specified action with arguments.
971 /// </summary>
972 /// <param name="action">Action name</param>
973 /// <param name="actionArgs">Action arguments</param>
974 public void Send(string action, IDictionary actionArgs)
976 ResetIsPostback();
977 InternalSend(action, actionArgs);
980 /// <summary>
981 /// Performs the specified action, which means:
982 /// <br/>
983 /// 1. Define the default view name<br/>
984 /// 2. Run the before filters<br/>
985 /// 3. Select the method related to the action name and invoke it<br/>
986 /// 4. On error, execute the rescues if available<br/>
987 /// 5. Run the after filters<br/>
988 /// 6. Invoke the view engine<br/>
989 /// </summary>
990 /// <param name="action">Action name</param>
991 /// <param name="actionArgs">Action arguments</param>
992 protected virtual void InternalSend(string action, IDictionary actionArgs)
994 // If a redirect was sent there's no point in
995 // wasting processor cycles
997 if (Response.WasRedirected) return;
999 if (logger.IsDebugEnabled)
1001 logger.DebugFormat("InternalSend for action '{0}'", action);
1004 bool checkWhetherClientHasDisconnected = ShouldCheckWhetherClientHasDisconnected;
1006 // Nothing to do if the peer disconnected
1007 if (checkWhetherClientHasDisconnected && !IsClientConnected) return;
1009 IControllerLifecycleExecutor executor =
1010 (IControllerLifecycleExecutor) context.Items[ControllerLifecycleExecutor.ExecutorEntry];
1012 if (!executor.SelectAction(action, Name, actionArgs))
1014 executor.PerformErrorHandling();
1016 executor.Dispose();
1018 return;
1021 executor.ProcessSelectedAction(actionArgs);
1025 /// <summary>
1026 /// Gives a chance to subclasses to format the action name properly
1027 /// <seealso cref="WizardStepPage"/>
1028 /// </summary>
1029 /// <param name="action">Raw action name</param>
1030 /// <returns>Properly formatted action name</returns>
1031 internal virtual string TransformActionName(string action)
1033 return action;
1036 private bool ShouldCheckWhetherClientHasDisconnected
1040 MonoRailConfiguration conf = (MonoRailConfiguration)
1041 context.GetService(typeof(MonoRailConfiguration));
1043 return conf.CheckClientIsConnected;
1047 /// <summary>
1048 /// To preserve standard Action semantics when using ASP.NET Views,
1049 /// the event handlers in the CodeBehind typically call <see cref="Send(String)"/>.
1050 /// As a result, the <see cref="IsPostBack"/> property must be logically
1051 /// cleared to allow the Action to behave as if it was called directly.
1052 /// </summary>
1053 private void ResetIsPostback()
1055 _resetIsPostBack = true;
1058 #endregion
1060 #region Action Invocation
1062 /// <summary>
1063 /// Pendent
1064 /// </summary>
1065 /// <param name="action"></param>
1066 /// <param name="actions"></param>
1067 /// <param name="request"></param>
1068 /// <param name="actionArgs"></param>
1069 /// <returns></returns>
1070 protected internal virtual MethodInfo SelectMethod(string action, IDictionary actions,
1071 IRequest request, IDictionary actionArgs)
1073 return actions[action] as MethodInfo;
1076 /// <summary>
1077 /// Pendent
1078 /// </summary>
1079 /// <param name="method"></param>
1080 /// <param name="methodArgs"></param>
1081 protected internal virtual void InvokeMethod(MethodInfo method, IDictionary methodArgs)
1083 InvokeMethod(method, context.Request, methodArgs);
1086 /// <summary>
1087 /// Pendent
1088 /// </summary>
1089 /// <param name="method"></param>
1090 /// <param name="request"></param>
1091 /// <param name="methodArgs"></param>
1092 protected internal virtual void InvokeMethod(MethodInfo method, IRequest request, IDictionary methodArgs)
1094 method.Invoke(this, new object[0]);
1097 #endregion
1099 #region Lifecycle (overridables)
1101 /// <summary>
1102 /// Initializes this instance. Implementors
1103 /// can use this method to perform initialization
1104 /// </summary>
1105 protected virtual void Initialize()
1107 IValidatorRegistry validatorRegistry =
1108 (IValidatorRegistry) serviceProvider.GetService(typeof(IValidatorRegistry));
1110 validator = CreateValidatorRunner(validatorRegistry);
1113 /// <summary>
1114 /// Performs application-defined tasks associated
1115 /// with freeing, releasing, or resetting unmanaged resources.
1116 /// </summary>
1117 public virtual void Dispose()
1121 /// <summary>
1122 /// Creates the default validator runner.
1123 /// </summary>
1124 /// <param name="validatorRegistry">The validator registry.</param>
1125 /// <returns></returns>
1126 /// <remarks>
1127 /// You can override this method to create a runner
1128 /// with some different configuration
1129 /// </remarks>
1130 protected virtual ValidatorRunner CreateValidatorRunner(IValidatorRegistry validatorRegistry)
1132 return new ValidatorRunner(validatorRegistry);
1135 /// <summary>
1136 /// Invoked by the view engine to perform
1137 /// any logic before the view is sent to the client.
1138 /// </summary>
1139 /// <param name="view"></param>
1140 public virtual void PreSendView(object view)
1142 if (view is IControllerAware)
1144 (view as IControllerAware).SetController(this);
1147 if (context != null && context.Items != null)
1149 context.Items[Constants.ControllerContextKey] = this;
1153 /// <summary>
1154 /// Invoked by the view engine to perform
1155 /// any logic after the view had been sent to the client.
1156 /// </summary>
1157 /// <param name="view"></param>
1158 public virtual void PostSendView(object view)
1162 #endregion
1164 #region Email operations
1166 /// <summary>
1167 /// Creates an instance of <see cref="Message"/>
1168 /// using the specified template for the body
1169 /// </summary>
1170 /// <param name="templateName">
1171 /// Name of the template to load.
1172 /// Will look in Views/mail for that template file.
1173 /// </param>
1174 /// <returns>An instance of <see cref="Message"/></returns>
1175 public Message RenderMailMessage(string templateName)
1177 return RenderMailMessage(templateName, false);
1180 /// <summary>
1181 /// Creates an instance of <see cref="Message"/>
1182 /// using the specified template for the body
1183 /// </summary>
1184 /// <param name="templateName">
1185 /// Name of the template to load.
1186 /// Will look in Views/mail for that template file.
1187 /// </param>
1188 /// <param name="doNotApplyLayout">If <c>true</c>, it will skip the layout</param>
1189 /// <returns>An instance of <see cref="Message"/></returns>
1190 public Message RenderMailMessage(string templateName, bool doNotApplyLayout)
1192 IEmailTemplateService templateService = (IEmailTemplateService)
1193 ServiceProvider.GetService(typeof(IEmailTemplateService));
1195 return templateService.RenderMailMessage(templateName, Context, this, doNotApplyLayout);
1198 /// <summary>
1199 /// Attempts to deliver the Message using the server specified on the web.config.
1200 /// </summary>
1201 /// <param name="message">The instance of System.Web.Mail.MailMessage that will be sent</param>
1202 public void DeliverEmail(Message message)
1206 IEmailSender sender = (IEmailSender) ServiceProvider.GetService( typeof(IEmailSender) );
1208 sender.Send(message);
1210 catch(Exception ex)
1212 if (logger.IsErrorEnabled)
1214 logger.Error("Error sending e-mail", ex);
1217 throw new RailsException("Error sending e-mail", ex);
1221 /// <summary>
1222 /// Renders and delivers the e-mail message.
1223 /// <seealso cref="DeliverEmail"/>
1224 /// </summary>
1225 /// <param name="templateName"></param>
1226 public void RenderEmailAndSend(string templateName)
1228 Message message = RenderMailMessage(templateName);
1229 DeliverEmail(message);
1232 #endregion
1234 internal class EmptyController : Controller
1236 public EmptyController(IRailsEngineContext context)
1238 InitializeFieldsFromServiceProvider(context);