Tigraine
Daniel Hoelbling talks about .NET

DefaultValue attribute for Castle MonoRail

August 4th, 2009 . by Daniel Hölbling

While reading through ScottGu’s announcement of the ASP.NET MVC 2 Preview 1 I noticed this rather interesting little feature that’s in there:

DefaultValue attribute in ActionMethod

MonoRail is much smarter about action methods than MVC so there are already things going on with default values through routing etc. But this particular thing wasn’t in the framework until now. So I took Ken Egozi’s sample about using IParameterBinder to implement the DefaultValueAttribute in MonoRail.

The result in syntax is identical to ASP.NET MVC 2 P1 and it was very easy to do:

public void Browse([DefaultValue("beer")] string category, [DefaultValue(1)] int page)
{
    
}

How is this done? Well, I suggest you read Ken Egozi’s post since he does a much better job at explaining that thing. Anyway, here is the code to make that happen:

using System;
using System.Reflection;
using Castle.MonoRail.Framework;

[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
public class DefaultValueAttribute : Attribute, IParameterBinder
{
	private readonly object value;
	public DefaultValueAttribute(object value)
	{
		this.value = value;
	}

	public int CalculateParamPoints(IEngineContext context, IController controller, IControllerContext controllerContext, ParameterInfo parameterInfo)
	{
		var token = context.Request[parameterInfo.Name];
		if (CanConvert(parameterInfo.ParameterType, token))
			return 10;
		return 0;
	}

	private static bool CanConvert(Type targetType, string token)
	{
		if (token == null)
			return false;

		try
		{
			Convert.ChangeType(token, targetType);
			return true;
		}
		catch (FormatException)
		{
			return false;
		}
	}

	public object Bind(IEngineContext context, IController controller, IControllerContext controllerContext, ParameterInfo parameterInfo)
	{
		string token = context.Request[parameterInfo.Name];
		Type type = parameterInfo.ParameterType;
		if (CanConvert(type, token))
			return Convert.ChangeType(token, type);
		return value;
	}
}

View Comments to “DefaultValue attribute for Castle MonoRail”

  1. comment number 1 by: James Curran

    I not sure about this, (as neither you nor Ken really explains CalculateParamPoints), but I think you are saying that, given the method:

    public void Browse([DefaultValue("beer")] string category, int page)

    then,
    /Home/Browser.rails?category=xxxx&page=2

    is a better match for that method than

    /Home/Browser.rails?page=2

    However, with the DefaultValue, both are equally good. The DefaultValue attribute shouldn’t affect how good a match a request is to a method, so it really should just return 0 for everything.

  2. comment number 2 by: Daniel Hölbling

    Very good point. I’ll try that out and possibly update the post.

  3. comment number 3 by: Daniel Hölbling

    Hmm.. actually a tough question.
    I’m not totally sold on making it’s weight 0. I see your point with the DefaultValue being a value after all so it shouldn’t matter if a parameter is passed or not, but setting it to 0 would also take away all the weight from that method overload..

    I’ll think about it a bit further and maybe we’ll continue this discussion on the castle mailing list :)

    Anyway, thanks for your comment!

  4. comment number 4 by: James Curran

    Thinking about this more, you are right.

    If we return 0, then
    /Home/Browser.rails?page=2
    would probably be a non-match for
    public void Browse([DefaultValue("beer")] string category, int page)
    which is not what we want.
    However, if we return 10, then for
    /Home/Browser.rails?page=2&source=db
    then
    public void Browse([DefaultValue("beer")] string category, int page)
    and
    public void Browse(int page, string source)
    become equally good, which is also not what we want.

    I think always returning 5 may work best, but mostly I think that this is going to require a bit more investigation of how CalculateParamPoints works. (I smell at least one of us getting a blog post out of that)


  5. [...] Curran pointed me at one interesting flaw with my implementation of the DefaultValueAttribute for MonoRail I blogged [...]

Leave a Reply

Name

Mail (never published)

Website

blog comments powered by Disqus