Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Create and update entities in Umbraco from code.
Subscribe to notifications to execute custom code on a number of operations.
Create, submit and handle HTML forms with controllers.
Using Tracing and MiniProfiler to debug your code.
General advice on source controlling your Umbraco implementation.
During the development of your Umbraco site you can debug and profile the code you have written to analyse and discover bottlenecks in your code.
To perform proper debugging on your site you need to set your application to have debug enabled. This can be done by setting Umbraco:CMS:Hosting:Debug="true"
for example in the appsettings.json
file:
Debug should always be set to false in production.
Tracing and trace logging are two names for the same technique. You need to configure which log messages you want to log.
Do not enable trace logging in your production environment! It reveals an awful lot of (sensitive) information about your production environment.
We recommend at least logging the following namespace at minimum (Verbose) level to enable valuable trace logging:
The logged messages can as always be monitored in the log viewer in backoffice
Umbraco includes the Mini Profiler project in its core (see https://miniprofiler.com for more details). The MiniProfiler profiles your code method calls, giving you a greater insight into code duration and query time for (for example) underlying SQL queries. It's great for tracking down performance issues in your site's implementation.
To display the profiler ensure that the configuration Umbraco:CMS:Hosting:Debug
is set to true
in the appSettings.json file. Thereafter you can add ?umbDebug=true
to the query string of any request.
Also, ensure your template calls @Html.RenderProfiler()
as one of the last things.
If you click 'Show Trivial' you can seen the kind of detail the MiniProfiler makes available to you about the execution path of your page:
and any underlying SQL Statements that are being executed for a part of the execution:
If you feel like a part of your application is slow you can use the MiniProfiler in your code to test the speed of it.
All you have to do is inject the IProfiler interface and add a step around your logic:
and now in the profiler you can see:
If you are using the Google Chrome browser you can install this Umbraco Productivity Tool Chrome Extension.
This will allow you to quickly switch between debugging with the MiniProfiler, Trace viewer and normal mode.
Learn how Umbraco writes log files and how you can write to them.
Information on creating forms in Umbraco
Creating forms requires that you know your way around .NET Core MVC. So if you are familiar with adding view models, views and controllers you are ready to make your first form.
You can also use Umbraco forms. It lets you and/or your editors create and handle forms in the backoffice. This includes setting up validation, redirecting and storing and sending form data. Great UI, extendable and supported by Umbraco HQ.
In this example we'll create a basic contact form containing a name, email and message field.
First, we're going to create the model for the contact form by adding a new class to the /Models
folder. If the folder doesn't already exist, create it at the root of your website. Let's call it ContactFormViewModel.cs
Build your solution after adding the model.
Next, we add the view for the form to the /View/Partials
folder. Because we've added the model and built the solution we can add it as a strongly typed view.
Name your view "ContactForm".
The view can be built with standard MVC helpers:
Finally, we're going to add the controller. Create a new empty class in the /Controllers
folder (if the folder doesn't already exist, create it at the root of the website). Name it ContactFormController
and make it inherit from SurfaceController
. Inheriting from SurfaceController
requires that you call its base constructor. If you are using an IDE: Integrated Development Environment, this can be done automatically.
If the model state is invalid, CurrentUmbracoPage()
will send the user back to the form. If valid, you can work with the form data, for example, sending an email to site admin and then RedirectToCurrentUmbracoPage();
.
You can add the form to a template by rendering the partial view:
To add the form to your site we'll make a macro. This also makes it possible to let editors add the form to a page using the rich text editor.
Go to the Settings section and right-click the Partial Views Macro Files node. Choose "Create" and select New partial view macro. Name the macro Contact Form.
In the partial view, we're going to render our contact form using the view model we created earlier.
The last thing to do before we can add the form to a page is to allow the Macro in a rich text editor. Expand the Macros node and select the Contact Form Macro. Check the boxes under Editor Settings.
If you don't see your new macro listed, right click Macros and select Reload.
Now you can add the form to a page that has a rich text editor.
Whenever you need to modify an entity that Umbraco stores in the database, there are a number of service APIs available to help you. This means that you can create, update and delete any of the core Umbraco entities directly from your custom code.
Services are typically defined using interfaces. Umbraco has them in the Umbraco.Cms.Core.Services
namespace, while the specific implementations can be found under the Umbraco.Cms.Core.Services.Implement
namespace. To use the service APIs you must first access them. Owing to the built-in dependency injection (DI) in ASP.NET Core, configured services are made available throughout Umbraco's codebase. This can be achieved via injecting the specific service you require - the service type or an interface.
If you are accessing Umbraco services inside your own controller class, you can add the Umbraco services that you need as constructor parameters. An instance of every service will be provided at runtime from the service container and by saving each one to a local field, you can make use of them within the scope of your class:
Inside a Razor View template, you can make use of a service injection into a view using the @inject
directive. It works similarly to adding a property to the view, and populating the property using DI:
If for instance we wish to subscribe to notifications on one of the services, we'd do so in a Composer C# class, where you will add a custom NotificationHandler
. In this custom NotificationHandler
we would inject the service we need into the public constructor of the class and Umbraco's underlying dependency injection framework will do the rest.
In this example we will wire up to the ContentService 'Saved' event, and create a new folder in the Media section whenever a new LandingPage is created in the content section to store associated media. Therefore we will need the MediaService available to create the new folder.
When you are creating your own custom class, in order to make use of the dependency injection framework, you need to register the ICustomNewsArticleService
service with the concrete type CustomNewsArticleService
. The AddScoped()
method registers the service with the lifetime of a single request.
There are several different ways that you can achieve the same outcome:
Register directly into the Startup.cs class.
Another approach is to create an extension method to IUmbracoBuilder
and add it to the startup pipeline.
Especially recommended when creating Umbraco packages as you won't have access to the Startup class, instead you can achieve the same as above by using a custom Composer which gives you access to the IUmbracoBuilder
.
Then your custom class eg. CustomNewsArticleService
can take advantage of the same injection to access services eg:
There is full API coverage of all Umbraco core entities:
Subscribing to notifications allows you to execute custom code on a number of operations both before and after the operation occurs
Subscribing to notifications allows you to execute custom code on a number of operations both before and after the operation occurs. All you need to follow this guide is an Umbraco installation with some content, e.g. the Umbraco starter kit.
Let's add a string of text to the log when a document is published. (The log is useful for debugging, different parts of the Umbraco codebase 'log' key events, warnings and errors to the log)
We react to notifications in Umbraco inside a notification handler, so let's create one. Add a new C# class to our project - call it LogWhenPublishedHandler and use : INotificationHandler<ContentPublishedNotification>
to identify our code as a handler, that will handle ContentPublishedNotification
. We'll need to add using Umbraco.Cms.Core.Events;
to the top of the .cs file and because the notifications that you can subscribe to in Umbraco are found in the core notifications namespace, we also need to add a using statement for that: using Umbraco.Cms.Core.Notifications;
.
We now have a class that looks like this:
However, we have an error and a red squiggly line under our class, this is because the INotificationHandler
interface expects us to implement a Handle
method for our notification. Let's create a public method called Handle
that takes a ContentPublishedNotification
as a parameter:
To check that this works, let's add a message to the log every time a content node is published.
We'll need to inject a Microsoft ILogger into our notification handler, by adding using Microsoft.Extensions.Logging;
to the top our file to add the required namespace, and creating a constructor for our handler that allows Umbraco to inject the logger:
Now we can use the logger to send a message to the logs:
We could log the name of each item that is being published too:
Now we have a notification handler that logs the name of a piece of content every time it's published, however, we're not done yet.
Umbraco needs to know that our handler exists and that it handles ContentPublishedNotification
, to tell Umbraco this, we open up the Startup.cs
file in the root of the project. First, we need to add using Umbraco.Cms.Core.Notifications;
to the top of this file as well, once we've done this we need to find the ConfigureServices
method. We now add .AddNotificationHandler<ContentPublishedNotification, LogWhenPublishedHandler>()
to the ConfigureServices
method right before the Build()
part. The method now looks like this:
The entire handler class should look like this:
Now we're ready to spin up our site and give it a try. Go to the Umbraco backoffice and publish a piece of content. Switch to the Settings section and find the Log Viewer in the Settings tree:
Search 'All Logs', and if all is wired up correctly you should discover your custom publish log message entries:
As you can see our custom code has been executed when we published a piece of content. It executed after the item was published because we used the ContentPublishedNotification
. If you want to run code before publishing, use ContentPublishingNotification
. The same goes for most other notifications so Saving
: Saved
, Copying
: Copied
and so forth.
In this article you can learn more about how to effectively source control your Umbraco site.
When you are running your site on Umbraco Cloud, source control is a part of the experience. Have a look at the 'Technical overview of an Umbraco Cloud Environment' and the information on 'Working with your Umbraco Cloud project' for a steer on Source/Version Control good practices.
If you are hosting your Umbraco implementation outside of Umbraco Cloud, it's generally considered good practice to set up source/version control for your site implementation files. This is especially a good idea when you are working with a team as it can help you track changes and manage conflicts with other developer's work.
So if you've made the decision to try to attempt to source/version control your Umbraco implementation work, perhaps setting up a 'Git Repository' - then a frequently asked question is:
There are lots of different possible variations within your working environment that will affect the best way to set up version control. It depends on whether you are:
Working with a team of developers.
How your development environment is set up.
Source control repository.
And also how you intend to build and deploy your solution to your target production environment (build servers, Web Deploy or good old File Transfer Protocol (FTP), etc).
However, Umbraco ships with a .gitignore
file with a custom Umbraco section, which will make git ignore the files for you. The Umbraco specific section looks like this:
For most projects, this gitignore will be enough, and this article will not be an exhaustive list of how to version control Umbraco in all possible scenarios.
However, we will go through the different files in order to give you an insight into the anatomy of an Umbraco website and therefore which parts to include in version control and which parts not to.
The main folder where the Umbraco CMS resides is the /umbraco
one inside your project.
Most of the files and folders within the Umbraco folder, is already added to the default gitignore file. As most of the Umbraco CMS core files are embedded, the /umbraco
folder contains primarily temporary files and log files, which are all added as Umbraco is installed.
We recommend that you follow the structure of the default gitignore file, and do not include any temporary files, log files or cache files to git.
Below are a set of general recommendations regarding the files within the /umbraco
folder.
/umbraco/data/TEMP
- This folder contains examine indexes, NuCache files, and so on, these are temporary and should not be committed.
/umbraco/Logs
- Umbraco currently uses Serilog, and a file will be generated in this folder containing trace logs of your application, one JSON file for each day.
/umbraco/mediacache
- ImageSharp ships with Umbraco and when an image is requested via the processor, for example, to be resized or cropped, a cached version of the transformed image will be stored in this folder. (The Imaging settings section allows you to determine where this cache is stored)
The main folder where the Umbraco CMS resides in, is the /umbraco
one inside your project.
Some of the contents change when you upgrade Umbraco, and will even be deleted and re-added on a clean and rebuild! No part of your implementation or third-party packages installed should update these folders.
From the gitignore above we can see that the content that will change when you upgrade Umbraco and be deleted and re-added on clean and rebuild are:
umbraco/UmbracoWebsite
umbraco/UmbracoInstall
umbraco/UmbracoBackoffice
umbraco/config/lang
umbraco/config/appsettings-schema.json
None of these folders should be committed to github since they will automatically be added on build. If you're working with an Integrated Development Environment (IDE) and a Build Server, it's NuGet's and MSBuild's job to restore the correct versions of these folders for you. If you don't use an IDE and prefer the command line you can use dotnet restore
to manually restore the NuGet packages.
But these are not the only files in the Umbraco folder that you should not commit to your git, some files are generated during runtime and should not be committed either, these are:
/umbraco/data/TEMP
- This folder contains examine indexes, NuCache files, and so on, these are temporary and should not be committed.
Umbraco.sdf
- If you are using SQL CE for the data store in your Umbraco site, then this file IS that datastore, it will be difficult to source control the constant changes to this file.
/umbraco/Logs
- Umbraco currently uses Serilog, and a file will be generated in this folder containing trace logs of your application, one JSON file for each day.
/umbraco/mediacache
- ImageSharp ships with Umbraco and when an image is requested via the processor, for example, to be resized or cropped, a cached version of the transformed image will be stored in this folder. (The Imaging settings section allows you to determine where this cache is stored)
We've now covered most of the folders within the /umbraco
folder, however, there are two left, the /umbraco/models
folder, and the /umbraco/PartialViewMacros
. The model's folder has its own section right below, but for the PartialViewMacros
folder, the answer to "should I commit this to git" is that it depends. If you want to change the templates within the folder or add your own, then you should commit it to git, if you don't need to do that, you should not, the build will automatically create it and its content.
The Umbraco wwwroot folder
The /wwwroot/umbraco
folder contains static assets for the backoffice, these files will be automatically created when you do a build, and should not be included in source control.
The strategy here will depend a little on which mode 'Umbraco Models Builder' you have opted to work with.
InMemoryAuto (default), The models are generated in memory, no source control is required.
SourceCodeManual and SourceCodeAuto, The models are generated in the /umbraco/models
folder of your project (or can be configured to be in a different folder or project), allowing you to track changes to the models in source/version control.
The Media section of Umbraco (unless configured otherwise) stores files in the /wwwroot/media
folder. These can be updated by editors, in the Umbraco backoffice, so generally speaking, you would not source control these files.
These are by default ignored by git.
The App_Plugins folder is the home for all third-party packages installed on your site.
Depending on how you installed the plugin it will affect how you choose to version control a particular third-party plugin:
Since plugins are installed via NuGet the installed files for individual plugins shouldn't need to be source controlled (and your deployment process should pull the packages implementation files from NuGet during the build and deployment process).
Each plugin could be different depending on its implementation and functionality. It may contain files that it would be useful to track via Source control, and also files that should be ignored: check with the plugin's supporting website/developer for more information.
A lot depends on how you maintain the front-end build of your website, e.g. are you using CSS preprocessors such as Sassy Cascading Style Sheets (SCSS)/ Leaner CSS (LESS) etc - gulp/grunt tasks to combine and minify script resources.
But generally, you will need to source control all your website's static assets: JavaScript, CSS, Fonts, Page Furniture Images, etc.
Umbraco site templates/views can be edited via the Umbraco Backoffice. They also reside in the /Views
folder on disk. As these views/templates often include code, it can make a lot of sense to have their changes tracked under source/version control.
However, this can pose a problem if the templates are updated via the backoffice outside of source control on the production environment.
This is not an advisable approach since often this will cause breaking changes to your website.
You would need to manually merge these files before considering a deployment.
Umbraco Cloud is a good solution in these scenarios, as changes via the backoffice are tracked in a Git repository automatically.
To source/version control changes to Macro implementation code, track the files in the following location:
Partial View Macros - stored in /Views/MacroPartials
as .cshtml files
Any supporting custom code for your application should be in version control, eg any of the following files
C# implementation,
Surface Controllers
API Controllers
ViewModels
Helpers / Extension Methods
Services etc.
Supporting class library projects,
Models generated by Modelsbuilder in SourceCodeManual or SourceCodeAuto mode.
Your site's appsettings.json
and appsettings.Development.json
files contain the configuration for your Umbraco site.
In general, it is recommended to add these to source control. When you do this, be sure that the file(s) doesn't contain any secrets, like API keys and connection strings. These can be added as needed, but omitted from any commits made to source control.
When you create and edit eg. Document Types, Media Types, and Data Types in the Umbraco Backoffice these values are stored in the Umbraco Database, making them difficult to source control in a 'file based' version control system.
There are a series of add-on packages that can help add source control to these structure changes:
The uSync package (free) - which can be configured to serialize these changes to files on disk, in a folder called /uSync - enabling you to source/version control these changes and synchronise them to other environments.
uSync Snapshots (licensed) - an extension to uSync, for taking 'before' and 'after' snapshots of an Umbraco site, for managing a release of a 'set of changes' between environments.
Umbraco Deploy on Premise - the on premise version of the package used by Umbraco Cloud.
In Umbraco we use the underlying logging framework of Serilog.
Out of the box, we write a JSON log file that contains a more detailed logfile. This allows tools to perform searches and correlations on log patterns more efficiently.
The default location of this file is written to umbraco/Logs
and contains the Machine name, along with the date too:
umbraco/Logs/UmbracoTraceLog.DELLBOOK.20210809.json
Serilog is a logging framework that allows us to do structured logging or write log messages using the message template format. This allows us to have a more detailed log message, rather than the traditional text message in a long txt file.
Here is an example of the same log message represented as JSON. More information is available and allows you to search and filter logs based on these properties with an appropriate logging system.
To learn more about structured logging and message templates you can read more about it over on the https://messagetemplates.org website. Alternatively watch this video from the Serilog creator - https://www.youtube.com/watch?v=OhmNp8UPEEg
Umbraco writes log messages, but you are also able to use the Umbraco logger to write the log file as needed. This allows you to gain further insights and details about your implementation.
Here is an example of using the logger to write an Information message to the log. It will contain one property, Name, which will output the name variable that is passed into the method.
If you are Logging and using the MiniProfiler, you can inject IProfilingLogger
that has a reference to both ILogger and IProfiler.
The incorrect way to log the message would be use string interpolation or string concatenation such as
The bad examples above will write to the log file, but we will not get a separate property logged with the message. This means we can't find them by searching for log messages that use the message template We are saying hello to {Name}
Serilog uses levels as the primary means for assigning importance to log events. The levels in increasing order of importance are:
Verbose - tracing information and debugging minutiae; generally only switched on in unusual situations
Debug - internal control flow and diagnostic state dumps to facilitate pinpointing of recognised problems
Information - events of interest or that have relevance to outside observers; the default enabled minimum logging level
Warning - indicators of possible issues or service/functionality degradation
Error - indicating a failure within the application or connected system
Fatal - critical errors causing complete failure of the application
Serilog can be configured and extended by using the .NET Core configuration such as the AppSetting.json files or environment variables. For more information, see the Serilog config article.
Learn more about the logviewer dashboard in the backoffice and how it can be extended.
This is a tool for viewing & querying JSON log files from disk in the same way as the built in log viewer dashboard.
Umbraco ships with the following Serilog projects, where you can find further information & details with the GitHub readme files as needed.
If you are interested in learning more then the following resources will beneficial:
Seq This is free for a single machine such as your own local development computer