• IDictionary and the Brail View Engine

    I spent a lot of time trying to figure out that the brail engine assumes IList on indexed properties. If you have a IDictionary you need to use the get_Item method like:

    ${notice.Params.get_Item("user").Value}

    </p>

    Not:

    ${notice.Params["user"].Value}
  • Changes Needed for Castle.MonoRail to use jQuery

    To get jQuery as the JS library for monorail I need to do the following:

    1. Get the JS files from jQuery and jQuery.Validation, save those to /Content/Js/ (or where ever).

    2. Implement the IMonoRailContainerEvents and IMonoRailConfigurationEvents interfaces on my GlobalApplication.cs file.

    3. In the Initialized method add:

    IAjaxProxyGenerator ajaxProxyGenerator = new JQueryAjaxProxyGenerator();
    container.ServiceInitializer.Initialize(ajaxProxyGenerator, container);
    container.AjaxProxyGenerator = ajaxProxyGenerator;
    1. In the Configure method add:
    configuration.JSGeneratorConfiguration.AddLibrary("jquery-1.2.1", typeof(JQueryGenerator))
        .AddExtension(typeof(CommonJSExtension))
        .ElementGenerator
            .AddExtension(typeof(JQueryElementGenerator))
            .Done
        .BrowserValidatorIs(typeof(JQueryValidator))
        .SetAsDefault();
    1. In the layout file reference the JS files like:
    <script language="javascript" type="text/javascript" src="${siteRoot}/Content/Js/jquery-1.2.6.min.js"></script>
    <script language="javascript" type="text/javascript" src="${siteRoot}/Content/Js/jquery.validate.min.js"></script>

    </p>

    1. Use the Castle trunk source.

    References:

    http://hammett.castleproject.org/?p=238

    http://groups.google.co.nz/group/castle-project-users/browse_thread/thread/eb5bb0e5b4560a97

    http://endurotracker.blogspot.com/2008/09/jquery-and-monorail.html

    http://www.nabble.com/jquery-proxy-generator-in-trunk-td19670846.html

  • Publishing video as FLV using a SWF Player

    This task turned out to be much more complicated then I would have expected. First just creating the video took a fair amount of time, trial, and error. I used CamStudio to capture the screen video and then the trial of Video Editor 8.

    After that was done I ended up using Any Video Converter to convert the file to FLV. Then I needed a SWF player to embed in the web page. I looked at a couple of options, but ended up with OS Flv. Once that was done and working, I ran into one last issue, resolved here. IIS doesn’t serve FLV files by default, so I needed to add the mime type.

  • Awesome Child Bike Seat – iBert [off topic]

    This is off topic. We recently started using an iBert child seat to take our son on bike rides with us. It’s a front mounted seat, which makes it really easy to control the bike, plus the child gets a better view. Our son loves it and even puts up with a helmet on it.  You need to make sure it will mount on your bike, mountain and road bikes may not work. It requires an inch or two of open stem space on the neck of the bike. I think most hybrid bikes will work, but make sure you double check. We bought it from amazon and so far we’re all loving it!

  • Get the selected radio button value using prototype

    Assuming you have a set of radio buttons with the same id, you can use the following to get the value of the selected/checked button.

    var value = null;
    $$(‘#plan_plan’).each( function(i) {</p>
    
    
    
    
    <span class="kwrd">if</span> ($F(i)) { value = $F(i); }
    

    } );

  • Not using Linq to it’s fullest can produce the worst of both worlds

    I’m parsing some XML and need to do one thing if there are a group of XML elements with the same name and another thing if just one element with a given name.

    Here my first attempt, yuck!

    XElement on = null;
    foreach (XElement element in elements.OrderBy(x => x.Name.LocalName))
    {</p>
    
    
    
    
    var current = element;
    <span class="kwrd">if</span> (elements.Count(x => current.Name.LocalName.Equals(x.Name.LocalName)) > 1)
    {
        <span class="kwrd">if</span> (on == <span class="kwrd">null</span> || !current.Name.LocalName.Equals(on.Name.LocalName))
        {
            <span class="kwrd">yield</span> <span class="kwrd">return</span> <span class="kwrd">new</span> JProperty(current.Name.LocalName,
                                       <span class="kwrd">new</span> JArray(
                                        elements.Where(x => current.Name.LocalName.Equals(x.Name.LocalName)).Select(
                                            x => <span class="kwrd">new</span> JValue(x.Value))));
            on = current;
        }
    }
    <span class="kwrd">else</span>
    {
        <span class="kwrd">yield</span> <span class="kwrd">return</span> FromElement(element);
    }
    

    }

    That's really bad, Linq is probably making the code worse. After some refactoring...

    foreach (var group in from e in elements group e by e.Name.LocalName)
        if (group.Count() > 1)
            yield return new JProperty(group.First().Name.LocalName,
                new JArray(from x in @group select new JValue(x.Value)));
        else
            yield return FromElement(group.First());

    The code here is easier to read shorter and clearer. Much better.

  • What’s Needed for Castle Validation To Work

    Make sure the view knows what to validate

    The object or object type to be validated must be sent to the view.

    PropertyBag["signuptype"] = typeof(SignupInfo);
    // or
    PropertyBag["signup"] = new SignupInfo;

    Remember to use Flash if redirecting, like in the case of a validation error on the server side.

    Make sure the JS files are included

    Either just include the files with a script tags:

    <script type="text/javascript" src="${siteroot}/Content/js/prototype.js"></script>
    <script type="text/javascript" src="${siteroot}/Content/js/scriptaculous.js"></script>
    <script type="text/javascript" src="${siteroot}/Content/js/formhelper.js"></script>
    <script type="text/javascript" src="${siteroot}/Content/js/behaviour.js"></script>

    Or using the InstallScripts method of the respective helpers. With the brail view engine it would be:

    ${Ajax.InstallScripts()}        
    ${Scriptaculous.InstallScripts()}        
    ${FormHelper.InstallScripts()}

    Make sure to use the FormHelper

    Make sure you use the FormHelper for at least the start and end form tags, but it should be used for the fields too if you want the values auto populated on an exception.

    ${Form.FormTag({@area:'', @controller:'WaitingList', @action:'AddToList', @immediate:'true', @useLabels:'true'})}
    <?brail OutputSubView('/shared/errorsummary') ?>
    <div class="formrow">
    ${Form.LabelFor("signup.Name", "Name:")}
    ${Form.TextField("signup.Name", {@style: 'width: 300px;'})} <br/>
    </div>
    <div class="formrow">
    ${Form.LabelFor("signup.Email", "Email Address:")}
    ${Form.TextField("signup.Email", {@style: 'width: 300px;'})} <br/>
    </div>
    <div class="formrow">
    ${Form.Submit("Add Me")}
    </div>
    ${Form.EndFormTag()}

    The immediate and useLabels are optional arguments for the validation JS.

    Make sure your controller class inherits  SmartDispatchController

    This will already be the case most of the time, but SmartDispatchController knows to validate the bound objects.

    public class WaitingListController : SmartDispatcherController

    Make sure you have validation attributes on your Model

    There are a lot of build in validation attributes and a way to add custom attributes. There is also a way to bind the validation to a model without attributes, but I’m not going to cover that here.

    public class EmailInfo
    {
        [ValidateNonEmpty]
        public string Name { get; set; }
    
        [ValidateNonEmpty, ValidateEmail]
        public string Email { get; set; }
    }

    The Validation Attributes are in the Castle.Components.Validator namespace.

    Make sure you check validation on your Action

    You will most likely already have a DataBind attribute on your model parameter, but you will need to add Validate = true. Within you action, check if you have validation errors and redirect to the form if you do. Be sure to Flash the model instance and the error summary. This is important as the client might have disabled javascript and because some validators are server side only.

    public void AddToList([DataBind("signup", Validate=true)] EmailInfo emailInfo)
    {
        if (HasValidationError(emailInfo))
        {
            Flash["signup"] = emailInfo;
            Flash["summary"] = GetErrorSummary(emailInfo);
            RedirectToAction("index");
            return;
        }
    
        EmailAddress address = new EmailAddress(emailInfo.Name, emailInfo.Email);
        _waitingListRepository.Put(address);
    
        WaitingListAdminController.WAITING_LIST_KEY);
        Redirect("waitinglist", "onlist");
    }

    Unit Testing

    Unit testing is obviously not required for this to work. If you are testing and using the TestSupport classes with BaseControllerTest you will need to add the following before calling your action to test an invalid model instance. There may be a better way to test this, but here’s what I did.

    [Test]
    public void Add_To_List_Expect_Validate_Fail_Redirect()
    {
        EmailInfo info = new EmailInfo();
    
        if (!_controller.Validator.IsValid(info))
            _controller.PopulateValidatorErrorSummary(info, _controller.Validator.GetErrorSummary(info));
                    
        _controller.AddToList(info);
            
        Assert.That(Response.WasRedirected);
        Assert.That(Response.RedirectedTo, Is.EqualTo("/Controller/index.castle"));
    }

    There’s a lot covered here, but really it’s not much more code then what you’d have without validation and you get a robust validation framework with both client and server side validation.