Typed access to Umbraco Marco parameters in Partial Views

In an Umbraco PartialViewMacroPage any Macro parameters are typed as:

IDictionary<string, object>

This makes for some rather messy code when trying to retrieve these parameters. Consider a Partial View Macro that takes two parameters:

The purpose of this Macro is going to be to output the following using Razor:

@days days before @date.ToString("dd MMM") ago it was
 @date.Subtract(TimeSpan.FromDays(days)).ToString("dd MMM")

You'd register the parameters above with Umbraco and render the Macro as follows.

@Umbraco.RenderMacro("DaysFromDate", new { days = 10, date = "2014/01/01" })

Note: one could pass the date parameter as a DateTime rather than a string, but as we'll see it ends up being passed to our view as a string anyway.

So now, here is the code to retrieve the values of our parameters in the partial view:

var days = string.IsNullOrEmpty((string) Model.MacroParameters["days"]) 
        ? 0 : Convert.ToInt32(Model.MacroParameters["days"]);
    
var date = string.IsNullOrEmpty((string) Model.MacroParameters["date"]) 
        ? DateTime.Now : DateTime.Parse((string) Model.MacroParameters["date"]);

Pretty nasty, but we have to do the above because:

A dig around the Umbraco core reveals the following that will assist us with type conversion:

var attemptDate = Model.MacroParameters["date"].TryConvertTo(typeof(DateTime));
var actualDate = attemptDate.Success ? (DateTime) attemptDate.Result : DateTime.Now;

So still a bit verbose for me, so we use extension methods that allow us to do the following:

var date = Model.MacroParameters.GetValue("date", DateTime.Now);
var days = Model.MacroParameters.GetValue("days", 2);

Note: the return type is implied by the type of the second argument (which is the default value if no macro parameter is passed). You can also use the extension methods in the following form:

var date = Model.MacroParameters.GetValue<DateTime>("date", DateTime.Now);
var days = Model.MacroParameters.GetValue<int>("days");

The first example above demonstrates that you can pass a type for readability even though it is implicit - the second, shows that you can use the method without a specified default value in which case you get the default value for the given type.

So finally the definitions for the extension methods:

public static class UmbracoExtensions
{
    public static T GetValue<T>(this IDictionary<string, object> dictionary, string key)
    {
        return dictionary.GetValue(key, default(T));
    }

    public static T GetValue<T>(this IDictionary<string, object> dictionary, string key, T defaultValue)
    {
        if (!dictionary.ContainsKey(key) || string.IsNullOrEmpty(dictionary[key].ToString())) 
            return defaultValue;

        return (T)Convert.ChangeType(dictionary[key], typeof(T));
    }
}

I'd like these in the Umbraco core. Would you?

Comments

Leave a comment