fredag 27 februari 2009

Potentially dangerous Request in MVC

While developing an admin-page in MVC I kept getting the old "Potentially dangerous Request..." which occurs when trying to submit form data including html tags.

After adding the "validateRequest=false" to the pages-element in web.config (which turns this feature off in asp.net webforms) and checking that the page directive didn't ovveride this setting I was getting quite annoyed that I still got the exception on my page.

However - in MVC you need to set an attribute on your action in the controller to turn off validation:

[ValidateInput(false)]
public ActionResult Edit(int id, FormCollection collection)
{}


In my opionon I think that the setting is web.config should be read by the MVC actions as well as you otherwise need to define this attribute on all actions that might include html as a string parameter.

tisdag 17 februari 2009

JavaScript context binding

One of the neatest features in the JavaScript library Prototype is its helper function for context binding. This is one feature to which I have yet to find the correspondence in jQuery. The following code is the functional equivalent of the Prototype solution, which I've found use for too many times:

<script type="text/javascript">
Function.prototype.bind = function(context)
{
   var __method = this;
   var __args = new Array();

   for(it = 1; it < arguments.length; it++)
      __args.push(arguments[it]);

   return function() {
      for(ait = 0; ait < arguments.length; ait++)
         __args.push(arguments[ait]);

      __method.apply(context, __args)
   };
}
</script>
So what does it do? Well, it makes sure that all functions will have a function of their own, called bind. Bind receives a context, and makes sure that the function is always invoked from that context - i.e. that the "this." notation in the function will always reference the given context.

This solves a common JavaScript problem, when working with callback functions. Consider the following:

function User(username, password)
{
   this.username = username;
   this.password = password;
   this.tryLogin = function()
   {
      $.ajax({
         type: "POST",
         url: "Default.aspx/Login",
         ...
         success: function(msg)
         {
            if(msg == 'true')
               alert('Welcome '+this.username);
         }
   }
}
In the above code, the function passed along as a callback will be called from the jQuery AJAX handler, hence "this.username" will look for a username property in $.ajax() (and presumably fail to find one). Now, if we had included the snippet at the top of this entry, we would've been able to modify the callback declaration to the following:

success: function(msg)
{
   alert('Welcome '+this.username);
}.bind(this);
Here, instead of passing in assigning the success property with function x, we're passing x to bind, and assigning the value that bind returns, which is x hooked up to a specified context (this, as passed to bind).

For added value, bind also comes with the option to specify additional arguments to be passed along to the function, as it is being invoked. To demonstrate why this is useful, consider the following scenario:

<button id="btn0">Button0</button>
<button id="btn1">Button1</button>
<button id="btn2">Button2</button>
<script type="text/javascript">
function Person(name) {
   this.name = name;
   this.logClick = function(x) {
      alert(this.name + ' clicked button ' + x);
   };
   this.start = function() {
      for(var i = 0; i < 3; i++)
      {
         $('#btn'+i).onclick = function() { this.logClick(i) }.bind(this);
      }
   };
}

var p = new Person('Test');
p.start();
</script>
Now, the start function will hook up the three buttons with onclick events that will trigger the highlighted function. The bind is there, so we will be able to access this.name in logClick without a problem, but our desired effect here - to get Button1, say, to alert "Test clicked button 1" - will still not be met: the i parameter won't be accessed until the actual click event occurs, and by then, the for loop will have completed, and i will have the value of "3". All buttons will produce the same output. What we want, here, is to tell the function to use the value that the variable contained at the time of the event wireup. Again, bind comes to the rescue:

$('#btn'+i).onclick = function(x) { this.logClick(x) }.bind(this, i);
The above modification will solve the issue, and produce the desired output. Now that we're binding the parameter in bind, we can, of course, get rid of the delegate entirely:

$('#btn'+i).onclick = this.logClick.bind(this, i);