The developer section of the Umbraco backoffice holds a dashboard named "Health Check". It is a handy list of checks to see if your Umbraco installation is configured according to best practices. It's possible to add your custom built health checks. This feature has been available since Umbraco version 7.5.
For inspiration when building your own checks you can look at the checks we've built into Umbraco. Some examples will follow in this document.
Umbraco comes with the following checks by default:
inline
true
cmsContentXml
RemoteOnly
On
enabled="false"
debug="false"
umbracoUseSSL
Each check returns a message indicating whether or not the issue in question has been found on the website installation, and if so whether the concern is an error that should be fixed, or less importantly, a warning you should be aware of.
Some of them can also be rectified via the dashboard, simply be clicking the Fix button and in some cases providing some required information. These changes usually involve writing to configuration files that will often trigger a restart of the website.
You can build your own health checks. There are two types of health checks you can build: configuration checks and general checks.
Each health check is a class that needs to have a HealthCheck attribute. This attribute has a few things you need to fill in:
HealthCheck
These are fairly simple, small checks that take an XPath query and confirm that the value that's expected is there. If the value is not correct, clicking the "Rectify" button will set the recommended value. An example check:
Umbraco.Web.HealthCheck.Checks.Config.AbstractConfigCheck
FilePath
XPath
ValueComparisonType
ValueComparisonType.ShouldEqual
ValueComparisonType.ShouldNotEqual
Values
ShouldEqual
IsRecommended = true
ShouldNotEqual
CheckSuccessMessage
CheckErrorMessage
RectifySuccessMessage
LocalizedTextService
~/Config/Lang/en-US.user.xml
~/Umbraco/Config/Lang
~/Config/Lang/*-*.user.xml
An example check:
using System.Collections.Generic; using System.Linq; using Umbraco.Core.Services; namespace Umbraco.Web.HealthCheck.Checks.Config { [HealthCheck("D0F7599E-9B2A-4D9E-9883-81C7EDC5616F", "Macro errors", Description = "Checks to make sure macro errors are not set to throw a YSOD (yellow screen of death), which would prevent certain or all pages from loading completely.", Group = "Configuration")] public class MacroErrorsCheck : AbstractConfigCheck { private readonly ILocalizedTextService _textService; public MacroErrorsCheck(HealthCheckContext healthCheckContext) : base(healthCheckContext) { _textService = healthCheckContext.ApplicationContext.Services.TextService; } public override string FilePath { get { return "~/Config/umbracoSettings.config"; } } public override string XPath { get { return "/settings/content/MacroErrors"; } } public override ValueComparisonType ValueComparisonType { get { return ValueComparisonType.ShouldEqual; } } public override IEnumerable<AcceptableConfiguration> Values { get { var values = new List<AcceptableConfiguration> { new AcceptableConfiguration { IsRecommended = true, Value = "inline" }, new AcceptableConfiguration { IsRecommended = false, Value = "silent" } }; return values; } } public override string CheckSuccessMessage { get { return _textService.Localize("healthcheck/macroErrorModeCheckSuccessMessage", new[] { CurrentValue, Values.First(v => v.IsRecommended).Value }); } } public override string CheckErrorMessage { get { return _textService.Localize("healthcheck/macroErrorModeCheckErrorMessage", new[] { CurrentValue, Values.First(v => v.IsRecommended).Value }); } } public override string RectifySuccessMessage { get { return _textService.Localize("healthcheck/macroErrorModeCheckRectifySuccessMessage", new[] { Values.First(v => v.IsRecommended).Value }); } } } }
This can be anything you can think of, the results and the rectify action are completely under your control.
Umbraco.Web.HealthCheck.HealthCheck
GetStatus()
HealthCheckStatus
HealthCheckAction
Name
Description
StatusResultType.Success
StatusResultType.Error
StatusResultType.Warning
StatusResultType.Info
ExecuteAction
using System; using System.Collections.Generic; using System.IO; using System.Web; using System.Web.Hosting; using Umbraco.Core.Logging; using Umbraco.Core.Services; namespace Umbraco.Web.HealthCheck.Checks.SEO { [HealthCheck("3A482719-3D90-4BC1-B9F8-910CD9CF5B32", "Robots.txt", Description = "Create a robots.txt file to block access to system folders.", Group = "SEO")] public class RobotsTxt : HealthCheck { private readonly ILocalizedTextService _textService; public RobotsTxt(HealthCheckContext healthCheckContext) : base(healthCheckContext) { _textService = healthCheckContext.ApplicationContext.Services.TextService; } public override IEnumerable<HealthCheckStatus> GetStatus() { return new[] { CheckForRobotsTxtFile() }; } public override HealthCheckStatus ExecuteAction(HealthCheckAction action) { switch (action.Alias) { case "addDefaultRobotsTxtFile": return AddDefaultRobotsTxtFile(); default: throw new ArgumentOutOfRangeException(); } } private HealthCheckStatus CheckForRobotsTxtFile() { var success = File.Exists(HttpContext.Current.Server.MapPath("~/robots.txt")); var message = success ? _textService.Localize("healthcheck/seoRobotsCheckSuccess") : _textService.Localize("healthcheck/seoRobotsCheckFailed"); var actions = new List<HealthCheckAction>(); if (success == false) actions.Add(new HealthCheckAction("addDefaultRobotsTxtFile", Id) // Override the "Rectify" button name and describe what this action will do { Name = _textService.Localize("healthcheck/seoRobotsRectifyButtonName"), Description = _textService.Localize("healthcheck/seoRobotsRectifyDescription") }); return new HealthCheckStatus(message) { ResultType = success ? StatusResultType.Success : StatusResultType.Error, Actions = actions }; } private HealthCheckStatus AddDefaultRobotsTxtFile() { var success = false; var message = string.Empty; const string content = @"# robots.txt for Umbraco User-agent: * Disallow: /umbraco/"; try { File.WriteAllText(HostingEnvironment.MapPath("~/robots.txt"), content); success = true; } catch (Exception exception) { LogHelper.Error<RobotsTxt>("Could not write robots.txt to the root of the site", exception); } return new HealthCheckStatus(message) { ResultType = success ? StatusResultType.Success : StatusResultType.Error, Actions = new List<HealthCheckAction>() }; } } }