Minor changes to improve testability of helpers
[castle.git] / MonoRail / Castle.MonoRail.Framework / Attributes / DataBindAttribute.cs
blobde09cc1d0c384afae8832b3d26bdf4fac7b35961
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.Reflection;
20 using Castle.Components.Binder;
22 /// <summary>
23 /// Defines where the parameters should be obtained from
24 /// </summary>
25 public enum ParamStore
27 /// <summary>
28 /// Query string
29 /// </summary>
30 QueryString,
31 /// <summary>
32 /// Only from the Form
33 /// </summary>
34 Form,
35 /// <summary>
36 /// From QueryString, Form and Environment variables.
37 /// </summary>
38 Params
41 /// <summary>
42 /// The DataBind Attribute is used to indicate that an Action methods parameter
43 /// is to be intercepted and handled by the <see cref="Castle.Components.Binder.DataBinder"/>.
44 /// </summary>
45 /// <remarks>
46 /// Allowed usage is one per method parameter, and is not inherited.
47 /// </remarks>
48 [AttributeUsage(AttributeTargets.Parameter, AllowMultiple=false, Inherited=false)]
49 public class DataBindAttribute : Attribute, IParameterBinder
51 private ParamStore from = ParamStore.Params;
52 private string exclude = string.Empty;
53 private string allow = string.Empty;
54 private string prefix;
55 private bool validate;
57 /// <summary>
58 /// Creates a <see cref="DataBindAttribute"/>
59 /// with an associated prefix. The prefix must be present
60 /// in the form data and is used to avoid name clashes.
61 /// </summary>
62 /// <param name="prefix"></param>
63 public DataBindAttribute(string prefix)
65 this.prefix = prefix;
68 /// <summary>
69 /// Gets or sets the property names to exclude.
70 /// </summary>
71 /// <remarks>The property name should include the <i>prefix</i>.</remarks>
72 /// <value>A comma separated list
73 /// of property names to exclude from databinding.</value>
74 public string Exclude
76 get { return exclude; }
77 set { exclude = value; }
80 /// <summary>
81 /// Gets or sets the property names to allow.
82 /// </summary>
83 /// <remarks>The property name should include the <i>prefix</i>.</remarks>
84 /// <value>A comma separated list
85 /// of property names to allow from databinding.</value>
86 public string Allow
88 get { return allow; }
89 set { allow = value; }
92 /// <summary>
93 /// Gets or sets a value indicating whether
94 /// the target should be validate during binding.
95 /// </summary>
96 /// <value><c>true</c> if should be validated; otherwise, <c>false</c>.</value>
97 public bool Validate
99 get { return validate; }
100 set { validate = value; }
103 /// <summary>
104 /// Gets or sets <see cref="ParamStore"/> used to
105 /// indicate where to get the values from
106 /// </summary>
107 /// <value>The <see cref="ParamStore"/> type.
108 /// Typically <see cref="ParamStore.Params"/>.</value>
109 public ParamStore From
111 get { return from; }
112 set { from = value; }
115 /// <summary>
116 /// Gets the databinding prefix.
117 /// </summary>
118 /// <remarks>
119 /// The prefix is a name followed by a
120 /// dot that prefixes the entries names
121 /// on the source http request.
122 /// </remarks>
123 /// <value>The databinding prefix.</value>
124 public string Prefix
126 get { return prefix; }
129 /// <summary>
130 /// Implementation of <see cref="IParameterBinder.CalculateParamPoints"/>
131 /// and it is used to give the method a weight when overloads are available.
132 /// </summary>
133 /// <param name="controller">The controller instance</param>
134 /// <param name="parameterInfo">The parameter info</param>
135 /// <returns>Positive value if the parameter can be bound</returns>
136 public int CalculateParamPoints(SmartDispatcherController controller, ParameterInfo parameterInfo)
138 CompositeNode node = controller.ObtainParamsNode(From);
140 IDataBinder binder = CreateBinder();
142 return binder.CanBindObject(parameterInfo.ParameterType, prefix, node) ? 10 : 0;
145 /// <summary>
146 /// Implementation of <see cref="IParameterBinder.Bind"/>
147 /// and it is used to read the data available and construct the
148 /// parameter type accordingly.
149 /// </summary>
150 /// <param name="controller">The controller instance</param>
151 /// <param name="parameterInfo">The parameter info</param>
152 /// <returns>The bound instance</returns>
153 public virtual object Bind(SmartDispatcherController controller, ParameterInfo parameterInfo)
155 IDataBinder binder = CreateBinder();
157 ConfigureValidator(controller, binder);
159 CompositeNode node = controller.ObtainParamsNode(From);
161 object instance = binder.BindObject(parameterInfo.ParameterType, prefix, exclude, allow, node);
163 BindInstanceErrors(controller, binder, instance);
164 PopulateValidatorErrorSummary(controller, binder, instance);
166 return instance;
169 /// <summary>
170 /// Creates the binder.
171 /// </summary>
172 /// <returns></returns>
173 protected virtual IDataBinder CreateBinder()
175 return new DataBinder();
178 /// <summary>
179 /// Configures the validator.
180 /// </summary>
181 /// <param name="controller">The controller.</param>
182 /// <param name="binder">The binder.</param>
183 protected void ConfigureValidator(SmartDispatcherController controller, IDataBinder binder)
185 if (validate)
187 binder.Validator = controller.Validator;
189 else
191 binder.Validator = null;
195 /// <summary>
196 /// Populates the validator error summary.
197 /// </summary>
198 /// <param name="controller">The controller.</param>
199 /// <param name="binder">The binder.</param>
200 /// <param name="instance">The instance.</param>
201 protected void PopulateValidatorErrorSummary(SmartDispatcherController controller, IDataBinder binder, object instance)
203 if (validate)
205 controller.PopulateValidatorErrorSummary(instance, binder);
209 /// <summary>
210 /// Binds the instance errors.
211 /// </summary>
212 /// <param name="controller">The controller.</param>
213 /// <param name="binder">The binder.</param>
214 /// <param name="instance">The instance.</param>
215 protected void BindInstanceErrors(SmartDispatcherController controller, IDataBinder binder, object instance)
217 if (instance != null)
219 controller.BoundInstanceErrors[instance] = binder.ErrorList;