Strongly Typed Models (1) - Intro

Tuesday, June 23, 2015 8:15 AM umbraco

It's the next cool thing, even better than Code First, and everybody wants them at some point: Strongly Typed Models. You have heard about them, you are slightly confused because they seemed to mean different things depending on who you were talking to, and you are not 100% sure you know why you would want them.

This should be the first of a group of posts, trying to make things clearer.

What is the problem?

Retrieving a content from the front-end cache yields an IPublishedContent object. That is, a real class (but you should not care), which implements that interface. And what is an IPublishedContent really?

It is an interface that exposes pretty much everything that makes up a content in Umbraco: its content type, its identifier, the date it was created... along with links to the parent and children contents 1. And so you can write in your views:

<div>Content was created on @content.CreateDate</div>
<div>Parent was created on @content.Parent.CreateDate</div>

The interface also exposes properties... and properties are tricky. In order to render the value of that text body we entered in the content editor, we need to write the following code:

<div>@(content.GetPropertyValue<IHtmlString>("textBody"))</div>

Don't laugh.

C# is a strongly typed language. Unlike PHP or Ruby, it cannot "invent" properties on the fly, and so there is no way we can write content.TextBody and have it automagically return the converted value of the proper CLR type.

That syntax is verbose, annoying, error-prone, and totally counter-intuitive. It forces you to remember that "textBody" is your property alias and that, due to the magic of some property converters, the value will be of type IHtmlString.

This is the problem we are trying to solve.

Dynamics

Since version 4.something, when Razor views were introduced, Umbraco supports dynamic views, ie views where Model is of type dynamic. Have a look at the following code:

@{
  IPublishedContent content = ...;
}
<div>@content.TextBody</div>

It will not even compile, because IPublishedContent does not have a property named TextBody. On the other hand, the following code will compile:

@{
  dynamic content = ...;
}
<div>@content.TextBody</div>

By using the dynamic type, we tell the CLR that we have no idea what content is, really. So please wait until the code actually runs, and only at that time try to find a property named "TextBody". This is called late binding—and it is what languages such as PHP or Ruby do.

The CLR offers various ways to let you control how it finds those properties at runtime, and what value it should return. Meaning that, under the hood, Umbraco can try and figure out whether the underlying IPublishedContent object has a property named "TextBody", and effectively return its value. Problem solved.

However, dynamics have a few downsides. Consider the following code:

<div>@content.TxetBody</div>

Notice the typo? That will get unnoticed at compile time. So, the view compiles, but you have no idea whether it will work or not, until it runs (ah, the joy of hunting for typos in PHP views...). And... what should Umbraco do at that time? Throw an exception? Silently return nothing?

Also:

@content.OrderDate.

What happens when pressing that last dot? OrderDate is a DateTime property in Umbraco, so surely Intellisense is proposing the appropriate DateTime methods, right? No. If content is dynamic, we will know the type of OrderDate for sure only at runtime. Dynamics are contagious: everything they touch becomes dynamic, and loses Intellisense.

Add to it an impact on performances, lots of issues with extension methods... and you will understand that although dynamics do solve the problem to some extend, we are still looking for a better solution.

To be continued!


  1. IPublishedContent also contains some plumbing to support the "content set" notion, which allows one to do eg content.IsFirst() in foreach loops. Also, parent and children are not "pure" references to other objects, but retrieve them on-demand. These are reasons why IPublishedContent is not really a POCO. 

comments powered by Disqus