Typed access to Umbraco Marco parameters in Partial Views

May 13, 2014

This is an old archived post, content maybe out of date, links may be broken and layout may be broken.

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:

  • Date - any date
  • Days - a number of days to subtract from the date

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:

  • If a parameter is registered on a Macro but not passed then we get an empty string
  • If the parameter is passed it is passed to us as a string and we need to do the conversion

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

Robert Foster - May 13, 2014

Looks good - done a pull request yet? :)

Darren - February 01, 2015

A variation is now in the core

Nick - May 01, 2016

What is the core variation, Darren? I haven’t been able to find it.

Leave a Comment

Comments are manually moderated and added once reviewed.

© 2021 Darren Ferguson, Built with Gatsby.