HasValue is not a nullcheck
I stumbled across this “issue” (I’m using quotations since it’s not really an issue) a while back when one of our sites would break for mysterious reasons which turned out to be related to how we'd used the HasValue extension method. So I thought I would share our mistake, why it happened and how to avoid it.
HasValue does not replace a nullcheck
Imagine we have a content page which has a properly called HeroImage (alias: heroImage) of type MediaPicker. And before we render our image we’re using HasValue("heroImage") to make sure that this property has a picked Media item that we can render in our frontend:
In this case HasValue(“heroImage”) returns true, which leads us to believe that the page has a picked Media item that we can render. So the next thing we do is try to render our Media item url in an image tag, using the property value converter:
YSOD:
Now our site breaks, saying that "Object reference not set to an instance of an object". Classic!
How is that possible? Our property had a picked Media item, why can’t I render it?
Content can be trashed!
The problem is that the picked Media item has been trashed by an editor in the back-office of Umbraco, so when we’re trying to convert the Media item to an IPublishedContent using the property value converter it’s going to return null because trashed content does not exist in the content cache.
The HasValue extension method doesn't care if the UDI (Umbraco identifier) for the picked content is published or trashed. It’s not its responsibility.
It’s not until you try to convert the value to an IPublishedContent that Umbraco will check if this item exists in the content cache (which only includes published content) that you can be 100% sure you can render this Media item on your frontend.
Not the solution:
At this point you might be tempted to just use ?.Url(), thinking you've found the solution to your problem:
While this would prevent your site from crashing, is not ideal because you would be rendering an empty image tag on your frontend, which is not pretty.
The solution:
Once you are aware of this “issue” the solution is simple: Always use a nullcheck as a compliment to the HasValue extension:
This way, we’re first checking if the page has a value at all and if it doesn’t we don’t bother trying to convert it to an IPublishedContent with the property value converter (which is a heavier operation).
But if it does have a value, we try to convert it to an IPublishedContent and then we nullcheck the result before we try to use the .Url() in our image tag.
Note: This example was using the MediaPicker but it could might as well be a ContentPicker or any other property type where you would want to convert the stored UDI to an IPublishedContent in a later sequence.
Hope it can help someone. ❤️
Cheers friends!