Archive

Archive for the ‘MonoRail’ Category

SubmittedWith Parameter Binder – Which button was clicked?

February 23, 2009 2 comments

What do you do when you want to have more than one button submit a form and vary the actions taken depending on the button press?

Previously I would have done something like:


bool resetFilter = QueryContainsKey( "ShowAll" );

where QueryContainsKey is a simple method that scans the query collection looking for the “ShowAll” key (when an html form is submitted, the name of the button is passed in the request, in the same way that other form elements are – just without a value).

This approach works reasonably well – except it’s kind of ugly, repetative (I need to apply the same logic in at least 3 controller methods) and makes testing painful as I have to remember to add a value to the Query collection.

Then I discovered the IParameterBinder interface (have a look at the DataBindAttribute code and Ken Egozi’s excellent tutorial) and built the following:

    [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
    public class SubmittedWithAttribute : Attribute, IParameterBinder
    {
        private readonly string _buttonName;

        public SubmittedWithAttribute(string buttonName)
        {
            _buttonName = buttonName;
        }

        public int CalculateParamPoints(IEngineContext context, IController controller, IControllerContext controllerContext, ParameterInfo parameterInfo)
        {
            if( parameterInfo.ParameterType.Equals( typeof(bool) ))
            {
                return 10;
            }

            return 0;
        }

        public object Bind(IEngineContext context, IController controller, IControllerContext controllerContext, ParameterInfo parameterInfo)
        {
            var collectionKeys = new List();

            if( context.Request.HttpMethod == "GET" )
            {
                collectionKeys.AddRange( context.Request.QueryString.AllKeys );
            }

            if( context.Request.HttpMethod == "POST" )
            {
                collectionKeys.AddRange(context.Request.Form.AllKeys);
            }

            // Keys must be compared using case insensitive comparer - html is not case sensitive and neither should this be
            collectionKeys.Sort(StringComparer.InvariantCultureIgnoreCase);
            return collectionKeys.BinarySearch( _buttonName, StringComparer.InvariantCultureIgnoreCase ) >= 0;
        }
    }
[/sourceode]

This allows you to define a controller method like:

[sourcecode language='csharp']
public void ViewResults(Guid questionnaireId, [DataBind("SurveyFilter")]SurveyFilterBuilder surveyFilterBuilder, [SubmittedWith( "ShowAll" )]bool resetFilter)
{
...
}

and test it just like any other method, but when the action is called from a form submit, resetFilter will indicate if the form was submitted using the ShowAll button.  The html form looks like:

$Form.FormTag("%{method='Get'}")
<fieldset>
...
<button type="submit" id="apply" title="Apply the filter to the report">Apply</button>
<button type="submit" id="showall" name="ShowAll" title="Show all results">Show all</button>
</fieldset>
$Form.EndFormTag()

Wicked!  Now I have collapsed a bunch of repeated logic into a simple attribute (that is tested) that has the added benefits of making my action method signatures more obvious and made my tests much cleaner.

Updated 24 Feb: Searching the key collection for the button name is now case-insensitive

Categories: MonoRail

MonoRail, Prototype validation and multiple submit buttons

May 2, 2008 3 comments

Previously I have discussed how I added action level filters to allow me to drop a cancel button on the page and worry about how the cancel was handled in the controller. This worked fine and did exactly as what I needed until I added client-side validation to the pages, the cancel button (being a submit button) triggered the validation.  To stop my cancel buttons triggering the validation I stopped the validator from automatically firing when the form was submitted by adding the following to the FormTag call:

$Form.FormTag( "%{action='processform', on_submit='false'}" )

To reconnect the validation and only validate the form if the button was not a cancel button, I used the following javascript that relies on the Prototype scripting library (I am using version 1.6.0.2).

/*
    Allows form validation while enabling the use of a submit button to
    cancel the page.
*/

// Register the validators once the form has loaded
Event.observe(window, 'load', RegisterValidationEventHandlers);

function RegisterValidationEventHandlers( event )
{
    if (window.prototypeValidators)
    {
        validatorsHash = $H(window.prototypeValidators);
        validatorsHash.values().each( function(value, index) {
            Event.observe(value.form, 'submit', validateFormIfNotCancelButton.bindAsEventListener(this));
        } );
    }
}

// Check if the event originated from a "cancel" button, if not proceed with normal validation
function validateFormIfNotCancelButton( event )
{
    var buttonClicked = document.activeElement || event.explicitOriginalTarget;
    var eventElementName = Element.readAttribute(buttonClicked, 'name');
    if(eventElementName != 'cancel')
    {
        var validator = prototypeValidators[event.element().id];
        validator.onSubmit( event );
    }
}

This first line registers an event listener on the window load event and executes the RegisterValidationEventHandlers function.

The RegisterValidationEventHandlers function checks for the existence of an associative array called prototypeValidators (automatically created by the PrototypeWebValidator) and if it is present, loops through attaching an event listener to the submit event for each form that has a validator. Note: for this to work, you will need to patch your PrototypeWebValidator as it currently creates an associative array from a normal array which is considered bad practice (see http://support.castleproject.org/browse/MR-440 for details).

The actual validation code is reasonably simple, retrieve the element that caused the event to fire, check it’s name and if it is not cancel, delegate the validation to the Prototype validator. The one interesting point to note is that there is no consistent mechanism to get the element that initiaited the submit, hence the var buttonClicked = document.activeElement || event.explicitOriginalTarget; which works in IE (document.activeElement) and FF (event.explicitOriginalTarget).

This script will work so long as you are using the default validation provider for MonoRail (prototype / dexagogo) and supports multiple forms without the need to add anything beyond suppressing the validation on submit behaviour via the additional property in the FormTag call.

Categories: MonoRail, Prototype

MonoRail and Castle Validator

April 14, 2008 Leave a comment

Recently I have been working to add validation to a web application I am building using MonoRail. A bit of research turned up a brilliant component created by Hammett that greatly simplifies adding client and server side validation in one place.

Hammett’s validation components work within the scope of the databinding operation that allows you to bind form fields directly into parameters in a reasonably seamless manner. You do need to be able to apply validation attributes to properties in the object being bound, so it does not appear that you can validate simple parameters, but I am using a presentation model for a majority of my forms so this was not a problem.

There is a great guide here and Hammett’s screencast here that show you how to set up the validation.

There are a couple of gotchas with the validation though, and these repeatedly tripped me up until I understood what was going on, so I will publish them here and hope that it helps someone else (all of these problems appear when doing server side validation only – I have deliberately disabled the client side validation until the server side validation is complete and correct):

Validation of simple properties happens before the value has been converted. This means the validator gets passed a string value and therefore does not always behave as expected. For example ValidateNotSameValue(CallResult.Unspecified) passes validation when a value of Unspecified is submitted because it compares Unspecified (the enum value) with “Unspecified” (a string value). My solution at the moment is to write type specific validators that extend ValidateNotSameValueAttribute and convert the value to a string that is passed to the validator (like this NotSameEnumValueValidator).

Validation only occurs if a value for the field is sent in the request. If no value is set, then the validation for that property is not triggered. For example I have a property called QuestionnaireId which must not be empty, this rule is enforced using a custom validator that ensures the value is a Guid and is not equal to Guid.Empty. The validator works (it is used in a number of other places), however it will not ensure a value is selected from a radio button group as no value is posted to the server for that form field (the databinder explicitly skips validation if there is no value to bind). I have not worked out a strategy for dealing with this yet.

I think Hammett has done a great job, and this component covers the basic scenarios as well as providing a good extensibility mechanism, however there are a few gotchas (even Hammett outlines a few here), the key is to be aware of what is happening and why.

Categories: MonoRail

Unit Testing MonoRail Controllers with PrincipalPermissions

March 19, 2008 3 comments

When you apply a CodeAccessSecurityAttribute that returns a PrincipalPermission to an action on a controller, all your existing tests for that action will break (to find out more about applying principal permissions, take a look at this blog entry about creating clean principal permission attributes). After a bit of digging and a lot of googling, I came across this post by Phil Haack that demonstrates how to set up your unit tests so they run correctly again.

Phil’s approach uses Rhino Mocks to mock out the IPrincipal and IIdentity interfaces and then attaches the mocked IPrincipal to Thread.CurrentPrincipal (which is where the PrincipalPermission retrieves the principal from to check permissions against). This approach is great, however I rapidly got tired of having to write out all of the code that this approach required, and I was getting annoyed with the clutter of try / finally blocks inside my tests (as well as forgetting to put the MockRepository into replay mode numerous times), so I stubbed out the principal and identity to create a much simpler alternative to the mocked versions. You can see these classes below:

    public class PrincipalStub : IPrincipal
{
    private readonly string _name;
    private readonly string _authenticationType;
    private readonly bool _isAuthenticated;
    private readonly bool? _isInRoleResponse;
    private readonly List<string> _roles;

    public PrincipalStub( string name, string authenticationType, bool isAuthenticated, bool isInRoleResponse )
    {
        _name = name;
        _isAuthenticated = isAuthenticated;
        _authenticationType = authenticationType;
        _isInRoleResponse = isInRoleResponse;
    }

    public PrincipalStub( string name, string authenticationType, bool isAuthenticated, params string[] roles )
    {
        _name = name;
        _isAuthenticated = isAuthenticated;
        _authenticationType = authenticationType;
        _roles = new List<string>( roles );
    }

    public IIdentity Identity
    {
        get
        {
            return new IdentityStub( _name, _authenticationType, _isAuthenticated );
        }
    }

    public bool IsInRole( string role )
    {
        if ( _isInRoleResponse.HasValue )
        {
            return _isInRoleResponse.Value;
        }

        return _roles.Contains( role );
    }
}

public class IdentityStub : IIdentity
{
    private readonly string _name;
    private readonly string _authenticationType;
    private readonly bool _isAuthenticated;

    public IdentityStub( string name, string authenticationType, bool isAuthenticated )
    {
        _name = name;
        _isAuthenticated = isAuthenticated;
        _authenticationType = authenticationType;
    }

    public string Name
    {
        get
        {
            return _name;
        }
    }

    public string AuthenticationType
    {
        get
        {
            return _authenticationType;
        }
    }

    public bool IsAuthenticated
    {
        get
        {
            return _isAuthenticated;
        }
    }
}

This means I can now replace the mocks and all the associated setup with a single line of code:
IPrincipal testPrincipal = new PrincipalStub("Test", "Test", true, true);

which will create a new principal that is always in any role asked of it (remember we want to test the action, not the code access security). This still left me with the setup and teardown code that I could have put into appropriate methods in the test class, but that lacked the flexibility to specify the exact parameters of the PrincipalStub for each test, and meant that all of my tests would be running under a “false” principal – less than ideal.What I needed was a mechanism for performing a two-phase operation with a chunk of indeterminate code in the middle, and the guarantee that the second phase would always run. Delegates and anonymous methods could have worked, but I got my inspiration from an approach Oren Eini (Ayende) uses to provide a more explicit mocking syntax. Taking this and applying it to the scenario I had resulted in the following TestPrincipalManger:

public class TestPrincipalManager
{
    private PrincipalStub _principal;

    public TestPrincipalManager(string username, string authenticationType, bool isAuthenticated, params string[] roles)
    {
        _principal = new PrincipalStub(username, authenticationType, isAuthenticated, roles);
    }

    public TestPrincipalManager(string username, string authenticationType, bool isAuthenticated, bool isInRoleResponse)
    {
        _principal = new PrincipalStub(username, authenticationType, isAuthenticated, isInRoleResponse);
    }

    public IDisposable Attach()
    {
        IPrincipal originalPrincipal = Thread.CurrentPrincipal;
        Thread.CurrentPrincipal = _principal;
        return new TestPrincipalCleanup( originalPrincipal );
    }

    public class TestPrincipalCleanup : IDisposable
    {
        private readonly IPrincipal _principal;

        public TestPrincipalCleanup( IPrincipal principal )
        {
            _principal = principal;
        }

        public void Dispose()
        {
            Thread.CurrentPrincipal = _principal;
            GC.SuppressFinalize( this );
        }
    }
}
That can be used as follows:

[Test]
public void AdministratorPermissionAttribute_Permission_Succeeds_If_Principal_Does_Have_Administrator_Permission()
{
    TestPrincipalManager authorisedPrincipal = new TestPrincipalManager("A.User", "Test Auth", true, "Administrator");
    AdministratorPermissionAttribute permissionsAttribute = new AdministratorPermissionAttribute( SecurityAction.Demand );
    IPermission permission = permissionsAttribute.CreatePermission();

    using ( authorisedPrincipal.Attach() )
    {
            Assert.IsTrue(Thread.CurrentPrincipal.IsInRole("Administrator"), "Pre-condition failed: Current user does not have the Administrator permission");
            permission.Demand();
    }
}
While at first glance, this appears to be a perversion of the using syntax / IDisposable interface, if you take a second look it makes perfect sense. Using is essentially just a compiler macro that replaces the using with a try / finally, and the object that we are disposing of is following the semantics of the dispose operation – it is cleaning up after itself. Extracting the class doing the disposal out means that the Attach() method can be called repeatedly with no nasty side-effects (I hope!).

Categories: MonoRail, Unit Testing

Creating Clean Principal Permission Attributes

March 18, 2008 1 comment

MonoRail allows you to use the PrincipalPermissionAttribute to secure your code in a reasonably unobtrusive manner as shown in the MonoRail documentation here. This is great as it allows a simple way to express the security requirements of your actions without cluttering the action with security checks. This problem I have with this is it adds a rather ugly attribute to the action that looks like:

[PrincipalPermission(SecurityAction.Demand, Role='Administrator')]
public void DoSomeAdminStuff()
{
    // ...
}
I also have to remember exactly how to type it out if I want to reuse it, so I set out to create a “nice” attribute that would communicate the same information with a lot less clutter – something like:

[RequireAdministratorPermission]
public void DoSomeAdminStuff()
{
    // ...
}
A quick bit of digging shows that the PrincipalPermissionAttribute is sealed so I can’t apply my usual trick of extending it and providing the default values I want, so I set about figuring out exactly what the PrincipalPermissionAttribute does. Turns out it is very simple, just extend the CodeAccessSecurityAttribute and implement IPermission CreatePermission(). Poking around in the PrincipalPermissionAttribute just to make sure I was doing things correctly, showed that I need to check if the underlying SecurityAttribute had it’s Unrestricted flag set and return an unrestricted permission if it was, so I extracted this into a superclass to simplify creating additional permission attributes later. The resulting classes are very simple and do not do much at all (except make my code look a lot nicer!).

public abstract class BasePrincipalPermissionAttribute : CodeAccessSecurityAttribute
{
    protected BasePrincipalPermissionAttribute( SecurityAction action ) : base( action )
    {
    }

    public override IPermission CreatePermission()
    {
        if (Unrestricted)
        {
            return new PrincipalPermission(PermissionState.Unrestricted);
        }

        return CreatePrincipalPermission();
    }

    protected abstract PrincipalPermission CreatePrincipalPermission();
}

public class AdministratorPermissionAttribute : BasePrincipalPermissionAttribute
{
    public ManageUsersPermissionAttribute( SecurityAction action ) : base( action )
    {
    }

    protected override PrincipalPermission CreatePrincipalPermission()
    {
        return new PrincipalPermission( null, "Administrator", true );
    }
}

And they can be used like:

[AdministratorPermission(SecurityAction.Demand)]
public void DoSomeAdminStuff()
{
    // ...
}

Unfortunately you still have to specify the security action, this is due to something that occurs during the compile process to serialise the permissions and store them with the assembly requiring the SecurityAction to be specified in the constructor of the attribute.

Categories: c#, MonoRail

Clean controllers with custom attributes

March 3, 2008 1 comment

It might be an obvious thing to do, but sometimes you miss the most obvious approaches…

Instead of repeatedly typing (copy and pasting!) [Filter(ExecuteEnum.BeforeAction, typeof(AuthenticationFilter)] for every controller you want to apply (in my case) the AuthenticationFilter to, spend 5 minutes building a custom attribute to do the work for you (I place these attribute classes in the same file as the filter):

public class ApplyAuthenticationFilterAttribute : FilterAttribute
{
    public ApplyAuthenticationFilterAttribute() : base ( ExecuteEnum.BeforeAction, typeof(AuthenticationFilter)
    {
    }
}

Now you leverage the IDE to do all the work for you (intellisense and code completion are the smart programmers copy / paste), and even if you only use it on one base controller, you still get the benefit of a nice attribute that you don’t even have to think about to understand…
[ApplyAuthenticationFilter]
public class MyController : Controller
{
    ...
}

vs
[Filter(ExecuteEnum.BeforeAction, typeof(AuthenticationFilter)]
public class MyController : Controller
{
    ...
}

The same approach can be used with layouts and rescues making your controllers “read” nicely
[UseDefaultLayout, UseGeneralError, ApplyAuthenticationFilter]
public class MyController : Controller
{
    ...
}

Categories: MonoRail

Adding Action Filters to MonoRail Controllers

March 3, 2008 5 comments

Update: See this post for making the cancel buttons work with client side validation

MonoRail has a rather nifty technique for adding cross-cutting concerns to controllers, it allows you to specify one or more filters to be run before or after the action, after rendering or always. Filters are commonly used for tasks like authentication and localisation, however by default they run for all actions in the controller and you must specify which actions to exclude using the [SkipFilter] attribute. In a majority of cases this works well as the filter is designed to handle cross-cutting concerns (which by definition affect most if not all actions), however there are times when you want to apply the filter to a minority of the actions in a controller, or add action specific metadata that may vary the way the filter executes depending on the action. Recently I came across just such a scenario…

In the surveying application that I am building, I needed to add a cancel button to a number of pages and be able to execute some cleanup logic or simply redirect the user to a different page. The buttons were embedded in the html as:

 <button name="cancel" type="submit">Cancel</button>

This meant that if the user pressed the cancel button, “cancel” will appear in the request parameters. Handling the cancel in the action specified in the form’s target is reasonably simple but I ended up with a lot of duplicated code at the top of my actions that wasn’t directly related to the goal of the action:

 bool isRequestCancelled = IsRequestCancelled( Request.Form );

if( isRequestCancelled )
{
  // do some cleanup here if required and redirect to cancel page
  return;
}

// do the actual work for the action

So I decided to split out the handling of the cancel button and put it into a filter. Sounds simple and after about half an hour of testing and coding I had something that resembled what I wanted, BUT, when I applied the filter directly to my actions it didn’t work. Back to the documentation and a bit of digging in the source code and I figure out that filter attributes are not parsed when the action metadata for a controller is created, meaning filters can be applied at the controller level only. While this is great for a majority of the cases where you use filters, I needed to be able to control the application of the filter at a much finer level of detail for each method (and the cancel button was an exception rather than a rule so adding [SkipFilter] everywhere would have led to some ugly controllers).Taking a step back, I realised the problem was essentially in 2 parts,

  1. processing the canceled request, and
  2. indicating how the canceled request was to be handled for each action.

This led me to create a filter to enable the cancellation of an action and a set of attributes that provided the additional metadata to the filter indicating how the cancellation should be handled.

The code for the filter then became relatively simple, check for cancel in the request, check for the attribute on the current action, redirect according to the attribute (note the attribute below the filter shows my preferred method for attaching filters to controllers):

public class ExecuteRedirectOnCancelFilter : IFilter
    {
        public bool Perform( ExecuteWhen exec, IEngineContext context, IController controller, IControllerContext controllerContext )
        {
            bool isRequestCancelled = FormContainsKey( context.Request.Form, "cancel" );
            if(!isRequestCancelled)
            {
                return true;
            }

            OnCancelRedirectToAttribute onCancel = GetCancellationDetails(controller);
            if(onCancel == null)
            {
                return true;
            }

            onCancel.Redirect( context.Response, controllerContext.Name);
            return false;
        }

        private bool FormContainsKey(NameValueCollection form, string key)
        {
            foreach (string formKey in form.AllKeys)
            {
                if (formKey.Equals(key))
                {
                    return true;
                }
            }

            return false;
        }

        private OnCancelRedirectToAttribute GetCancellationDetails(IController controller)
        {
            Controller mrController = controller as Controller;
            if (mrController == null)
            {
                throw new InvalidOperationException("The type of controller that the ExecuteRedirectOnCancelFilter has been applied to does not derive from Castle.Monorail.Framework.Controller.  The filter is unable to access the information necessary to execute.");
            }

            string currentActionName = mrController.Action;
            MethodInfo currentAction = mrController.MetaDescriptor.Actions[currentActionName] as MethodInfo;
            if (currentAction == null)
            {
                throw new InvalidOperationException("The method info for the currently executing action could not be retrieved.");
            }

            object[] redirectInfoAttributes =
                currentAction.GetCustomAttributes(typeof(OnCancelRedirectToAttribute), true);

            if (redirectInfoAttributes.Length == 0)
            {
                return null;
            }

            OnCancelRedirectToAttribute redirectInfoAttribute = (OnCancelRedirectToAttribute)redirectInfoAttributes[0];
            return redirectInfoAttribute;
        }
    }

    public class EnableRedirectOnCancelAttribute : FilterAttribute
    {
        public EnableRedirectOnCancelAttribute() : base( ExecuteWhen.BeforeAction, typeof(ExecuteRedirectOnCancelFilter) )
        {
        }
    }

The attribute simply allows us to specify a controller and action:

[AttributeUsage(AttributeTargets.Method, AllowMultiple=false)]
    public class OnCancelRedirectToAttribute : Attribute
    {
        private string _controller;
        private readonly string _action;

        public string Controller
        {
            get
            {
                return _controller;
            }
        }

        public string Action
        {
            get
            {
                return _action;
            }
        }

        public bool IsControllerSpecified
        {
            get
            {
                return !String.IsNullOrEmpty( _controller );
            }
        }

        public bool IsActionSpecified
        {
            get
            {
                return !String.IsNullOrEmpty( _action );
            }
        }

        public OnCancelRedirectToAttribute( string redirectToController, string redirectToAction )
        {
            _controller = redirectToController;
            _action = redirectToAction;
        }

        public virtual void Redirect(IRedirectSupport redirector, string currentController)
        {
            if(!IsControllerSpecified)
            {
                _controller = currentController;
            }

            if(!IsControllerSpecified || !IsActionSpecified)
            {
                throw new InvalidOperationException( "Unable to redirect the user after request was cancelled as the controller or action was not specified");
            }

            redirector.Redirect( _controller, _action );
        }
    }

    public class OnCancelRedirectToActionAttribute : OnCancelRedirectToAttribute
    {
        public OnCancelRedirectToActionAttribute( string redirectToAction ) : base( null, redirectToAction )
        {
        }
    }

    public class OnCancelRedirectToIndexAttribute : OnCancelRedirectToAttribute
    {
        public OnCancelRedirectToIndexAttribute( ) : base( null, "Index" )
        {
        }
    }

I have not performance tested this yet, however caching the attributes against the actions or parsing all of the controllers to generate a list of actions with the cancel attributes should be relatively easy to add at a later date if it is required.The technique could also be easily extended to a simple EnableActionFiltersFilter that simply determined if the current action had an ActionFilter attribute attached and delegated execution of the filter directly to the attribute, as demonstrated by the following aircode:

 public class EnableActionFiltersFilter : IFilter
    {
        public bool Perform( ExecuteWhen exec, IEngineContext context, IController controller, IControllerContext controllerContext )
        {
            ActionFilterAttribute actionFilter = GetActionFilter(controller);

            if(actionFilter == null)
            {
                return true;
            }

            return actionFilter.Perform( ExecuteWhen exec, IEngineContext context, IController controller, IControllerContext controllerContext );
        }

        private ActionFilterAttribute GetActionFilter(IController controller)
        {
            Controller mrController = controller as Controller;

            if (mrController == null)
            {
                throw new InvalidOperationException("The type of controller that the ActionFilter has been applied to does not derive from Castle.Monorail.Framework.Controller.  The filter is unable to access the information necessary to execute.");
            }

            string currentActionName = mrController.Action;
            MethodInfo currentAction = mrController.MetaDescriptor.Actions[currentActionName] as MethodInfo;
            if (currentAction == null)
            {
                throw new InvalidOperationException("The method info for the currently executing action could not be retrieved.");
            }

            object[] actionFilterAttributes = currentAction.GetCustomAttributes(typeof(ActionFilterAttribute), true);
            if (actionFilterAttributes .Length == 0)
            {
                return null;
            }

            ActionFilterAttribute actionFilter = (ActionFilterAttribute )actionFilterAttributes[0];
            return actionFilter;
        }
    }

    public class EnableActionFiltersAttribute : FilterAttribute
    {
        public EnableActionFiltersAttribute () : base( ExecuteWhen.Always, typeof(EnableActionFiltersFilter) )
        {
        }
    }

And the ActionFilterAttribute to perform the filter action:

[AttributeUsage(AttributeTargets.Method, AllowMultiple=false)]
    public abstract class ActionFilterAttribute : Attribute
    {
        public abstract bool Perform( ExecuteWhen exec, IEngineContext context, IController controller, IControllerContext controllerContext );
    }

Now you can simply extend the ActionFilterAttribute, override the Perform method and you have action level filters in your controller (you would also have to enable the action level filters on your controller using the EnableActionFilters attribute).

Categories: MonoRail

Windsor and NLog – Getting the Exception StackTrace

February 15, 2008 Leave a comment

Someone queried the NZ.NET mailing list yesterday about how to get the stack trace out of an exception logged via the NLog logging facility.

Having a quick look at the docs for layout renderers seemed to indicate that the ${exception} layout renderer, however by all accounts that wasn’t working so I’ve thrown together a couple of quick tests and a MonoRail site with Windsor integration enabled demonstrate how to achieve it and make sure it works. You can get the demo from the link below – it is a rar file but as WordPress won’t let me upload rar files, so I have changed the extension to .png. You will need to download it to your machine and change the file extension back to .rar to access the content.

Logging with NLog via Windsor

For those of you who just want to know what the configuration looks like:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <targets>
            <target name="debugconsole" xsi:type="Console" layout="${message}"/>
            <target name="errorconsole" xsi:type="Console" layout="${message} [br] Details:${exception:format=type,message,stacktrace:separator=[br]}"/>
        </targets>
        <rules>
            <logger name="*" level="Debug" writeTo="debugconsole"/>
            <logger name="*" level="Error" writeTo="errorconsole"/>
        </rules>
    </nlog>
</configuration>

The targets are both console targets because I temporarily redirect Console.Out to a StringWriter so that I can capture and display the logged data.

Be aware that this demo is built against a copy of the Castle trunk from mid January (all referenced assemblies are included in the download), if you are not seeing the same behaviours in your code, it may be due to differences (or an issue) in the version you are using.

Categories: Castle Windsor, MonoRail, NLog

0 to 60 in … 3 months

February 12, 2008 5 comments

In early December of last year I started working on a new web application designed to simplify telephone-assisted exit interviews. I don’t quite remember my rationale, but I made the choice to build the system using MonoRail (probably something to do with 5 or so years of WebForm inflicted pain). 3 months later I have a system that allows the user to log in, view the list of pending surveys, edit various details about a survey or employee and fill in a questionnaire on behalf of an employee; doesn’t sound like much does it?

MonoRail is hard, don’t let anyone tell you any different. You have to download a bunch of stuff, set it up on your machine, learn some weird new syntax for writing your web pages, you don’t get intellisense in your webpages, there’s no nice server controls, no drag and dropping to build the UI, the documentation doesn’t always show you how to get things done and much much more.

Still reading? Still thinking you want to use MonoRail in your next project? Good! Everything I said in that last paragraph is true, however it doesn’t cover the whole story.

When I started out using MonoRail, I read about most people’s experiences and got a warm fuzzy feeling – they all tell you it is great; I want to inject a little bit of realism here, starting out with MonoRail is hard work.  The key thing with MonoRail is, once you know how to setup and build a MonoRail application, nothing changes (unless you runoff the trunk and Hammett goes and changes a bunch of stuff – but that’s your own fault and a story for another day). Compare that to WebForms; you get everything out of the box, you can build your first “useful” page in minutes and the learning curve is quite shallow (depending on how heavily you use the designer). There’s a gotcha hidden in there though, over the entire time I spent building WebForms applications, I rarely had a “pleasant” experience where things just worked and I didn’t have to spend at least some of my week fighting the framework.  I think the biggest difference between MonoRail and WebForms is how soon using it becomes “easy”.

3 months on I have a web application that does everything I mentioned above as well as:

Still doesn’t sound like much – maybe it isn’t but here’s the thing, in the past 3 months I have done all the learning I need to build a reasonably scalable and robust solution, that means my productivity will keep accelerating as I get better at dealing with the domain and the business problems (Ayende has talked about this before but I cannot find the specific post I had in mind).

At the end of the day, I am glad I made the switch to MonoRail, developing is fun once again and I get to concentrate on solving the bits of the problem that should be solved, rather than fighting with the framework I’ve chosen to implement the solution with.  Hopefully I have set some realistic expectations about the initial investment required to get going with MonoRail, and given you an indication that the investment is well worth the gains in the end.

Categories: MonoRail
Follow

Get every new post delivered to your Inbox.