Permalink
Browse files

Replaced params dictionary population with a binder implementation

  • Loading branch information...
1 parent 4f9355d commit d84581521581657a996761ff357c272c4da418cc @casualjim casualjim committed Mar 28, 2009
View
3 .gitignore
@@ -20,5 +20,4 @@ IronRubyMvc/Controllers/._controller.rb
IronRubyMvc/Core/._RubyEngine.cs
dependencies/IronRuby.Tests.exe
dependencies/IronRuby.Tests.pdb
-IronRubyMvcLibrarySpecs/bin/*.*
-ParamsBinder.cs
+IronRubyMvcLibrarySpecs/bin/*.*
View
81 IronRubyMvc/Controllers/ParamsBinder.cs
@@ -0,0 +1,81 @@
+#region Usings
+
+using System.Collections.Generic;
+using System.Globalization;
+using System.Web.Mvc.IronRuby.Extensions;
+using Microsoft.Scripting;
+
+#endregion
+
+namespace System.Web.Mvc.IronRuby.Controllers
+{
+ public class ParamsBinder : IModelBinder
+ {
+ private IDictionary<SymbolId, object> _params;
+
+ #region IModelBinder Members
+
+ public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
+ {
+ controllerContext.EnsureArgumentNotNull("controllerContext");
+ bindingContext.EnsureArgumentNotNull("bindingContext");
+
+ _params = (bindingContext.Model as Dictionary<SymbolId, object>) ?? new Dictionary<SymbolId, object>();
+ bindingContext.ValueProvider.ForEach(pair =>
+ {
+ bindingContext.ModelState.SetModelValue(pair.Key, pair.Value);
+ _params.Add(pair.Key.ToSymbolId(), pair.Value.RawValue);
+ });
+// var request = controllerContext.HttpContext.Request;
+// var modelState = controllerContext.Controller.ViewData.ModelState;
+//
+// PopulateParamsWithFormData(request, modelState);
+// PopulateParamsWithQueryStringData(request, modelState);
+// PopulateParamsWithRouteData(controllerContext.RouteData.Values);
+
+ return _params;
+ }
+
+ #endregion
+
+// private void PopulateParamsWithFormData(HttpRequestBase request, IDictionary<string, ModelState> modelState)
+// {
+// foreach (string key in request.Form.Keys)
+// {
+// var symbolKey = SymbolTable.StringToId(key);
+// _params[symbolKey] = request.Form[key];
+// modelState.Add(key, CreateModelState(request.Form[key]));
+// }
+// }
+//
+// private void PopulateParamsWithQueryStringData(HttpRequestBase request, IDictionary<string, ModelState> modelState)
+// {
+// foreach (string key in request.QueryString.Keys)
+// {
+// var symbolKey = SymbolTable.StringToId(key);
+// var value = request.QueryString[key];
+// _params[symbolKey] = value;
+// modelState.Add(key, CreateModelState(value));
+// }
+// }
+//
+// private void PopulateParamsWithRouteData(IEnumerable<KeyValuePair<string, object>> routeValueDictionary)
+// {
+// foreach (var item in routeValueDictionary)
+// {
+// var key = SymbolTable.StringToId(item.Key);
+// _params[key] = item.Value;
+// }
+// }
+//
+// private static ModelState CreateModelState(string value)
+// {
+// return new ModelState {Value = CreateValueProviderResult(value)};
+// }
+//
+// private static ValueProviderResult CreateValueProviderResult(string value)
+// {
+// return new ValueProviderResult(value, value, CultureInfo.CurrentCulture);
+// }
+ }
+}
View
69 IronRubyMvc/Controllers/RubyController.cs
@@ -19,7 +19,7 @@ public class RubyController : Controller
{
private readonly Dictionary<object, object> _viewData = new Dictionary<object, object>();
private IRubyEngine _engine;
- private IDictionary<object, object> _params;
+ private IDictionary<SymbolId, object> _params;
public string ControllerName { get; internal set; }
public RubyClass RubyType { get; private set; }
@@ -30,13 +30,13 @@ public string ControllerClassName
}
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Params")]
- public IDictionary<object, object> Params
+ public IDictionary<SymbolId, object> Params
{
get
{
if (_params == null)
{
- PopulateParams();
+
}
return _params;
@@ -45,57 +45,19 @@ public string ControllerClassName
private void PopulateParams()
{
- //TODO: Possibly replace this with a binder implementation
+ var modelType = typeof (IDictionary<SymbolId, object>);
var request = ControllerContext.HttpContext.Request;
- _params =
- new Dictionary<object, object>(ControllerContext.RouteData.Values.Count +
- request.QueryString.Count + request.Form.Count);
- PopulateParamsWithRouteData();
-
- PopulateParamsWithQueryStringData(request);
-
- PopulateParamsWithFormData(request);
- }
-
- private void PopulateParamsWithFormData(HttpRequestBase request)
- {
- foreach (string key in request.Form.Keys)
- {
- var symbolKey = SymbolTable.StringToId(key);
- _params[symbolKey] = request.Form[key];
- ModelState.Add(key, CreateModelState(request.Form[key]));
- }
- }
-
- private void PopulateParamsWithQueryStringData(HttpRequestBase request)
- {
- foreach (string key in request.QueryString.Keys)
- {
- var symbolKey = SymbolTable.StringToId(key);
- var value = request.QueryString[key];
- _params[symbolKey] = value;
- ModelState.Add(key, CreateModelState(value));
- }
- }
-
- private void PopulateParamsWithRouteData()
- {
- foreach (var item in ControllerContext.RouteData.Values)
- {
- var key = SymbolTable.StringToId(item.Key);
- _params[key] = item.Value;
-// ModelState.Add(item.Key, CreateModelState(item.Value.ToString()));
- }
- }
-
- private static ModelState CreateModelState(string value)
- {
- return new ModelState {Value = CreateValueProviderResult(value)};
- }
-
- private static ValueProviderResult CreateValueProviderResult(string value)
- {
- return new ValueProviderResult(value, value, CultureInfo.CurrentCulture);
+ var binder = Binders.GetBinder(modelType);
+ var modelBindingContext = new ModelBindingContext
+ {
+ Model = new Dictionary<SymbolId, object>(ControllerContext.RouteData.Values.Count + request.QueryString.Count + request.Form.Count),
+ ModelName = "params",
+ ModelState = ModelState,
+ ModelType = modelType,
+ ValueProvider = ValueProvider
+ };
+ _params = binder.BindModel(ControllerContext, modelBindingContext) as IDictionary<SymbolId, object>;
+
}
internal void InternalInitialize(ControllerConfiguration config)
@@ -104,6 +66,7 @@ internal void InternalInitialize(ControllerConfiguration config)
_engine = config.Engine;
ControllerName = config.RubyClass.Name.Replace("Controller", string.Empty);
RubyType = config.RubyClass;
+ Binders = RubyModelBinders.Binders;
}
protected override void Execute(RequestContext requestContext)
View
59 IronRubyMvc/Controllers/RubyModelBinders.cs
@@ -0,0 +1,59 @@
+#region Usings
+
+using System.Collections.Generic;
+using System.Reflection;
+using Microsoft.Scripting;
+
+#endregion
+
+namespace System.Web.Mvc.IronRuby.Controllers
+{
+ public class RubyModelBinders
+ {
+ private static readonly ModelBinderDictionary _binders = CreateDefaultBinderDictionary();
+
+ public static ModelBinderDictionary Binders
+ {
+ get { return _binders; }
+ }
+
+ internal static IModelBinder GetBinderFromAttributes(ICustomAttributeProvider element, Func<string> errorMessageAccessor)
+ {
+ // this method is used to get a custom binder based on the attributes of the element passed to it.
+ // it will return null if a binder cannot be detected based on the attributes alone.
+
+ var attrs = (CustomModelBinderAttribute[]) element.GetCustomAttributes(typeof (CustomModelBinderAttribute), true /* inherit */);
+ if (attrs == null)
+ {
+ return null;
+ }
+
+ switch (attrs.Length)
+ {
+ case 0:
+ return null;
+
+ case 1:
+ var binder = attrs[0].GetBinder();
+ return binder;
+
+ default:
+ var errorMessage = errorMessageAccessor();
+ throw new InvalidOperationException(errorMessage);
+ }
+ }
+
+ private static ModelBinderDictionary CreateDefaultBinderDictionary()
+ {
+ // We can't add a binder to the HttpPostedFileBase type as an attribute, so we'll just
+ // prepopulate the dictionary as a convenience to users.
+
+ var binders = new ModelBinderDictionary
+ {
+ {typeof (IDictionary<SymbolId, object>), new ParamsBinder()},
+ {typeof (HttpPostedFileBase), new HttpPostedFileBaseModelBinder()}
+ };
+ return binders;
+ }
+ }
+}
View
27 IronRubyMvc/Extensions/StringExtensions.cs
@@ -1,6 +1,7 @@
#region Usings
using System.Globalization;
+using Microsoft.Scripting;
#endregion
@@ -46,6 +47,32 @@ public static string FormattedWith(this string value, params object[] parameters
return string.Format(CultureInfo.CurrentUICulture, value, parameters);
}
+ /// <summary>
+ /// Converts the string to a case-sensitive <see cref="SymbolId"/>
+ /// </summary>
+ /// <param name="value">The value.</param>
+ /// <returns></returns>
+ public static SymbolId ToSymbolId(this string value)
+ {
+ return ToSymbolId(value, true);
+ }
+
+ /// <summary>
+ /// Converts the string to a <see cref="SymbolId"/>
+ /// </summary>
+ /// <param name="value">The value.</param>
+ /// <param name="caseSensitive">if set to <c>true</c> the <see cref="SymbolId"/> will be case-sensitive.</param>
+ /// <returns></returns>
+ public static SymbolId ToSymbolId(this string value, bool caseSensitive)
+ {
+ return caseSensitive ? SymbolTable.StringToId(value) : SymbolTable.StringToCaseInsensitiveId(value);
+ }
+
+ /// <summary>
+ /// Ensures the argument not empty.
+ /// </summary>
+ /// <param name="value">The value.</param>
+ /// <param name="argumentName">Name of the argument.</param>
public static void EnsureArgumentNotEmpty(this string value, string argumentName)
{
if (value.IsNullOrBlank()) throw new ArgumentNullException(argumentName, "Cannot be null");
View
2 IronRubyMvc/System.Web.Mvc.IronRuby.csproj
@@ -90,8 +90,10 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Controllers\ControllerConfiguration.cs" />
+ <Compile Include="Controllers\ParamsBinder.cs" />
<Compile Include="Controllers\RubyActionMethodSelector.cs" />
<Compile Include="Controllers\RubyActionSelector.cs" />
+ <Compile Include="Controllers\RubyModelBinders.cs" />
<Compile Include="Core\AssemblyStreamContentProvider.cs" />
<Compile Include="Core\IPathProvider.cs" />
<Compile Include="Core\IRubyEngine.cs" />

0 comments on commit d845815

Please sign in to comment.