I've found myself thinking a lot about a good naming strategy or naming convention for website projects that works with data in several different formats. Before I start to outline my current ideas (might change over time) I would like to set the stage for the project.

Let's say we have a website project with the all of these "features":

  • A rich domain model with domain entities
  • A database to store state of the domain model including repositories
  • A MVC front end
  • A web api aimed for the front end website (not 3rd party integrations)
  • A public web api for 3rd party integration's

Now comes the challenge, all of these different touch points/end points into the system often needs to represent the same thing/entity. We've been taught that for one should not use the domain entity as view model in a MVC-view, we should have a dedicated type that acts as the view model, the problem is that each of these end points probably needs a dedicated type which presents us with a problem that I've had a really hard time to find a perfect solution for:

How should we name all these dedicated types/classes?

First of all, these special representations of the core rich domain model entities are all DTOs (data transfer objects) but since we probably need these DTOs to look different depending on the context we need to name them in a smart and understandable way. The goal would be that a developer should be able to understand what "type of DTO" the code is working with by looking at the type name.

So let's start with some ideas and let's say that the core domain model that we're working here is type called Car.

MVC-view model

This one is quite simple, a very common practice is to suffix the core entity with ViewModel.

Idea: CarViewModel.

Database mapping DTO

In most of my solutions I use a repository that will take in the domain model and store it's state, the repository also returns instances of domain entities. During this process we need to map the domain entity to a model that is suitable for the storage we're using. Let's say a database. So most of the time I would represent the database table as a DTO.

Idea: CarDto

Model for website frontend APIs

Here we're talking about features on the website that make async javascript requests to the backend, something like a filter, a search feature, auto suggest or what ever. These are "ApiModel" but they are used in a context where they've probably will end up as some kind of "view model" when they are rendered into the website. I'm quite sure that this kind of model is different from the model used in public APIs for 3rd parties, so I would like to use a naming convention for them that makes it clear that they are used only for the website.

Idea: CarFrontendModel

Model for public API for 3rd parties

Here we're talking about model types for a external public web api if we're implementing a API that is restful these models could be called a Resource or a ApiModel. I like the idea of calling the "Resource" since a restful api could/shuld have navigation-properties etc. So in this case the "CarResource" might have links to a BrandResource or a "DealerResource". I'm very hesitant about this one but one has to come up with something.

Idea: CarResource


I had two main purposes of writing this blog post, first one is to document and share my ideas and the second is to get input and/or feedback. If you feel that you have other thoughts around this, please share in the comments! 

Note: I might (and almost hope) that I'll change my conclusions above based on more experience and feedback.

 

 

When working with Umbraco Forms there are some scenarios when you want to extend the functionality to perform something custom. Every time a Form is submitted a new Record is created for this Form, this Record is stored in the database and also passed to all Workflows that are configured on the form.

In our case we wanted to implement a HoneyPot to avoid some of the SPAM that comes through the forms so in cases we wanted to be able to remove a record from a custom WorkflowType. I found some solutions for Umbraco 7 but non of these worked on Umbraco 8 so I got my hands dirty and started to implement this. 

I did not find a way to remove the Record from within the Workflows Execute()-method since everything I tried caused exceptions. I managed to solve it by firing of a Task that runs some time after the Record has been created. 

Here's the code that we used:

public class DeleteWorkflow : WorkflowType
{
    public DeleteWorkflow()
    {
        this.Id = new Guid("466BAB6D-ECF1-4BE8-B0E7-6C6ACC495565");
        this.Name = "Delete Record";
        this.Description = "Deletes the record from the Database";
        this.Icon = "icon-delete";
    }
    

    public override WorkflowExecutionStatus Execute(Record record, RecordEventArgs e)
    {
        Task.Run(() => DeleteRecordWithDelay(record.UniqueId.ToString(),record.Form.ToString()));

        return WorkflowExecutionStatus.Completed;
    }


    public override List<Exception> ValidateSettings()
    {
        return new List<Exception>();
    }

    
    public static async Task DeleteRecordWithDelay(string recordId,string formId)
    {
        await Task.Delay(5000);

        try
        {
        
            IRecordService recordService = DependencyResolver.Current.GetService<IRecordService>();
            IRecordStorage recordStorage = DependencyResolver.Current.GetService<IRecordStorage>();
            IFormService formService = DependencyResolver.Current.GetService<IFormService>();
        
            var form = formService.GetForm(Guid.Parse(formId));
            var record = recordStorage.GetRecordByUniqueId(Guid.Parse(recordId), form);
        

            recordService.Delete(record, form);
        }
        catch (Exception e)
        {

            var exception = e.Message;
            throw;
        }
    }
}

When you want to combine and minify your JavaScript and CSS there’s a lot of options out there. Mainly you can either do this in your build process or perform this “on demand” from the server side of your website. When it comes to performance the first option, to actually deploy the processed assets, is probably the most efficient but I often prefer to take the cost of processing this on the server side using something like Microsoft.AspNet.Web.Optimization or ClientDependency Framwork (ships with Umbraco).

In this post I’ll explain the steps needed to use Microsofts Web.Optimization-framework and the 3rd party package System.Web.Optimization.Less to be able to process use .less-files on the server.

Note: The Less-package that I’m using needs at least .NET Framework 4.6.1 to run, so before going further, make sure that you’re project runs on at least .NET Framework 4.6.1.

First of, we need to install the two packages that we’re going to use:

Install-Package Microsoft.AspNet.Web.Optimization
and

Install-Package System.Web.Optimization.Less


Note: If you're on Umbraco 7 you need to make sure that you're using the right versions of the packages, I would recommend installtion them in this order:

* Install-Package Microsoft.AspNet.Web.Optimization -version 1.1.3
* Install-Package dotless -version 1.5.2
* Install-Package System.Web.Optimization.Less -version 1.3.4

This is beacure the "dotless" package made breaking changes in version 1.6+ but some NuGet package does not explicity state the dependency to be for dotless < 1.6.

After installing these packages we need to configure our bundle during startup. For a vanilla MVC-project this would be done in Global.asax but when we're running Umbraco we can avoid having to fiddle with Global.asax by creating our own ApplicationEventHandler (for V7) or UserComponent (for V8).

Before we configure our bundles we need to make sure that the path we're using for our bundles is ignored by Umbraco, otherwise we might get issues with 404-responses from the bundle. Make sure the root web.config contains a appSettings that looks something like this: 

<add key="umbracoReservedPaths" value="~/umbraco,~/install/,~/bundles/"/>

 Then we can start to configure our bundle, when running Umbraco 7 it would look something like this

public class UmbracoStartup : ApplicationEventHandler
{
    protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
    {
        this.RegisterBundles(BundleTable.Bundles);
    }

    public void RegisterBundles(BundleCollection bundles)
    {
        bundles.Add(new ScriptBundle("~/bundles/js") 
            .Include("~/Scripts/site.js")
        );

        bundles.Add(new LessBundle("~/bundles/css")
            .Include("~/Style/site.less")
        );
    }
}

 Then in your views you'll render the bundle links like this:

@Styles.Render("~/bundles/css")

After this the bundle will be rendered on the front end of the website, please note that it behaves differently depending on the system.web -> compilation -> debug setting in the root web.config:

  • Debug = true (for development): Each file in the bundle is referenced with it's own <script>-tag
  • Debug = false (for production): Files and bundles (and minified if configured).

A good practice is to test both these settings in your development environment to make sure that everything works.

A very nice feature in the latest version of Umbraco (8.0+) is that they’ve made it really easy to implement your own CollectionBuilders. This raises two obvious questions:

What is a CollectionBuilder?

A collection builder is used to create a collection of Types, the main purpose being a collection of types that you would like to keep in a certain order. Umbraco uses this to register stuff like ContentFinders, Components and lots of other things.
The syntax looks something like this:

// Append
composition.Components().Append<MyCustomComponent>()
// Insert After
composition.Components().InsertAfter<MyCustomComponent,AnotherComponent>()

By leverage this feature you can create your own collection of types and make sure that the concrete instances in the collection is sorted in the way you want.

How would I implement a custom CollectionBuilder?

We’re basically looking at 3 small pieces that we need to get this in place. Let’s say that we have a type called ITextProcessor with multiple different implementations that we need to store in our custom collection in a given order. We’ll start with the collection it self by creating a new class that inherits from BuilderCollectionBase, all we need to do is to pass the type we want to store in the collection as a type parameter and implement the default constructor: 

public class TextProcessorsCollection : BuilderCollectionBase<ITextProcessor>
{
    public TextProcessorsCollection (IEnumerable< ITextProcessor > items) : base(items)
    {
    }
}

 Next up is the “Collection Builder” it self, here we inherit from “OrderedCollectionBuilderBase” and pass 3 type parameters:
1. The builder type it self
2. The collection type
3. The type of the items in the collection


And also implement one single property, “This”. It should look something like:

public class TextProcessorsCollectionBuilder :
OrderedCollectionBuilderBase< TextProcessorsCollectionBuilder, TextProcessorsCollection,ITextProcessor>
{
    protected override TextProcessorsCollectionBuilder This => this;
}

 The last thing we should do is to implement an extension method so the builder will be easy to use during composition, let’s create one like this:

public static class TextProcessorsCollectionExtensions
{
    public static TextProcessorsCollectionBuilder TextProcessors(this Composition composition)
=> composition.WithCollectionBuilder< TextProcessorsCollectionBuilder >();
}

After this we can work with our list during Composition using the extension method like so:

public class MySiteComposer : IUserComposer
{
    public void Compose(Composition composition)
    {
    composition.TextProcessors().Append<RemoveSpaceTextProcessor>();
    composition.TextProcessors().Append<AddLineBreaksTextProcessor>();
    }
}

 When we want to use the list in our code, we can get it from the IOC-container, prefferebly using consrtructor injection

public class MyController : SurfaceController
{
    public void MyController(TextProcessorsCollection textProcessors)
    {
        // Save as local variable
    }
}

Here's a summery of major features and improvements with each major/minor release of Umbraco CMS, you can see this as an overview of the great detailed release information that Umbraco HQ provides with each release.

 

Umbraco 7.0

Released: 2013-11-21

A major release that introduced the new AngularJS-based backoffice, new "property editors" for data types and a lot of improvements in the editor experience.

Release details on our

 

Umbraco 7.1

Released: 2014-04-03

This release was mainly a "polish"-release that fixed bugs and brought features that did not make it into 7.0.

  • Image Cropper in the core
  • Breadcrumbs and warnings (discard changed-dialog when leaving a view without saving)
  • Change document type
  • API: MemberService introduced.

Release details on our

 

Umbraco 7.2

Released: 2014-12-04

  • Grid property editor was added
  • Responsive preview mode (switch between desktop, mobile and tablet)

Release details on our

 

Umbraco 7.3

Released: 2015-09-29

  • Improved load balancing
  • Upgrade to MVC5 & WebApi2

Release details on our

 

Umbraco 7.4

Released: 2016-02-11

  • New Content Type (Document Type) editor
  • Models Builder

Release details on our

 

Umbraco 7.5

Released: 2014-08-17

  • Health Check dashboard introduced
  • 301 redirect manager
  • Image Processor security improvements
  • Password recovery for backoffice
  • Package Installer UI updated and "target version" for packages.
  • Sortable property types in list views

Release details on our

 

Umbraco 7.6

Released: 2017-05-02

  • New editor for scripts and templates
  • Content/media/members-pickers (property editors) was improved
  • Color-changes to backoffice UI
  • List View Pickers
  • UDIs was introduced

Release details on our

 

Umbraco 7.7

Released: 2017-09-19

This release introduced the new "User Management" and also changed some of the details around how users and passwords are stored. This version is "milestone" when upgrading old sites, I've had to install this specific version to the things right.

  • New User Management, more focus on settings on User Groups
    • Invite Users
    • Multiple Start Nodes
    • Big UI-improvements
  • Introduced "Content Templates"
  • New starterkit
  • Scheduled Health Checks
  • Includes Nested Content in the core
  • ISerachableTree-interface for custom search in the tree

Release details on our

 

Umbraco 7.8

Released: 2018-02-06

  • Backoffice Tours introduced (Step-by-step introductions/support)
  • The "Info"-tab replaced the "Generic Properties"-tab
  • Improvements to Load Balancing

Release details on our

 

Umbraco 7.9

Released: 2018-02-27

This released was called the "GDPR-release" and introduced some tooling around "consent" from visitors.

  • The ConsentService API was introduced
  • Logging of User actions in the backoffice was improved
  • Member properties can be marked as "Sensitive Data" and hidden from some backoffice User Groups.
  • Export Member data to a file

Release details on our

 

Umbraco 7.10

Released: 2018-03-27

This release does not contains a lots of features and was probably release to be able to ship the breaking change with TypedContent and Guids.

  • Improved performance for querying UmbracoHelper.TypedContent with Guids
  • Dropdown property editor was improved

Release details on our

 

Umbraco 7.11

Released: 2018-06-19

  • See where Composition Content Types are being used
  • Dictionary Tree modernized (aka moved from WebForms to AngularJS)
  • Multilingual tours
  • Cancel-events from ContentService-event handlers now shown to the user.

Release details on our

 

Umbraco 7.12

Released: 2018-08-14

  • Folders for Content Types (aka Document Types)
  • Nested Content filtering content types
  • Visual Color Picker for content type colors

Release details on our

 

Umbraco 7.13

Released: 2019-01-08

The "Community-release" with 172 improvements, bug fixes and so on.

  • SVG-support for media / media pickers
  • Better image search
  • Media item deletion detection (the "Trashed"-alert on media that has been deleted)
  • Media file type indicators (icons for doc,pdf etc)
  • Performance improvements, site-startup
  • UX: Color pickers improvements

Release details on our

 

Umbraco 7.14

Released: 2019-03-12

  • Multi Url Picker added to Core
  • Helth Check for TLS 1.2
  • UX-improvements to Image Cropper, SVG, Toggles and more

 

Release details on our

 

Umbraco 7.15

Released: 2019-07-09

The final Umbraco version 7 minor release. NOTE! This version was patched with 7.15.1 due to a bug in the media tree.

  • .NET Framework update to 4.5.2
  • New Preview engine
  • Updates to EntityService (breaking)
  • Pickers: "Ignore User Start Nodes"-setting
  • Bugfixes for CPU usage when not running the backoffice on the /umbraco-route

 

Release details on our

 

Umbraco 8.0

Released: 2019-02-26

A new major-version of Umbraco with lot's of updates and breaking changes. A cleaned up code base where all legacy code (aka WebForms) has been removed.

  • New backoffice UI
  • Introduced "Infinite Editing" - edit doctypes, media and content in a "modal" and not switch context.
  • Language Variants - Native support for 1:1-translations in the core
  • Removed all dynamics, UmbracoTemplatePage etc
  • Introduced "NuCache", no more XML (umbraco.config)
  • Introduced Composition and Components for startup and Dependency Injection

 

Release details on our

 

Umbraco 8.1

Released: 2019-07-09

  • Improved editor experiance
  • Nested Content - Copy & Paste
  • Easier access to MiniProfiler by a Settings-dashboard switch.
  • Ignore User Start Nodes
  • Accessibility improvements
  • Models Builder updates
  • Introduces IPublishedPropertyType, breaking change for PropertyValueConverters

 

Release details on our

 

Umbraco 8.2

Released: 2019-10-15

A total of 91 features and fixes in this release.

 

  • Rich Text Editor enhancements
    • Performance / loading time improved
    • Drag and drop images
    • Copy/paste from Word improved
  • Improved cache performance and stability

 

Release details on our

Umbraco 8.3

Released: 2019-11-12

A small minor release with a major feature added.

 

  • Allowing to change the culture of a language (ie. dialects English UK to English US) 
  • Disable renaming for built in User Groups

 

Release details on our

 

Umbraco 8.4

Released: 2019-12-10

A maintenance-release with dataType-tracking added, improved backoffice search and around 180 community contributions.

 

  • Fixes issue with outdates results from Content Service
  • Fixes redirects for moved content nodes
  • Allow to search by Content Guid

 

Release details on our

 

Umbraco 8.5

Released: 2020-01-14

The "Models Builder" in Core-release, note that there was some fast bug fix-releases after this was release.

 

  • Added a slime down version of Models Builder in the the Umbraco Core, used to be an external package.

 

Release details on our

This blog post came out of my work with packages for Umbraco CMS, but it's totally applicable even if you're not working with Umbraco. When building packages for Umbraco that works with custom tables you have to keep in mind that CMS supports different databases. We need to make sure that our queries works on both the standard SQL Server and with SQLCE.

I've decided to try to create a list of queries and map out what does and what doesn't work depending on the database type.

 

Description

Query

SQL Serv.

SQLCE

Regular SELECT

SELECT * FROM umbracoNode

x

x

SELECT with Subquery in select-statement

SELECT id
(SELECT COUNT(pk) from cmsDataType) as Test
FROM umbracoNode

x

 

SELECT with Subquery in WHERE-statement

SELECT id, [text]
FROM umbracoNode
WHERE Id IN (SELECT nodeId from cmsDataType)

x

x

SELECT with Subquery (scalar1) in WHERE

SELECT id, [text]
FROM umbracoNode
WHERE Id = (SELECT TOP 1 nodeId from cmsDataType)

x

 

SELECT with Inner Join

SELECT n.id, n.[text]
FROM umbracoNode n
INNER JOIN cmsDataType d ON d.nodeId = n.id

x

x

SELECT with STUFF-function

SELECT id,[text], STUFF([text],1,1, '')
FROM umbracoNode

x

x

SELECT TOP 

SELECT TOP 5 * FROM cmsContentType

x

x

SELECT with “FOR XML PATH”.
Will format as a scalar XML-payload

SELECT TOP 10 id,[text]
FROM umbracoNode
ORDER By [text]
FOR XML Path('node')

x

 

Row_Number() / Paging with
SELECT with ROW_NUMBER()

SELECT id,[text],
ROW_NUMBER() OVER (ORDER BY [text]) AS RowNumber
FROM umbracoNode
ORDER By [text]

x

 

Paging with
SELECT WITH OFFSET AND FETCH 2

SELECT id,[text]
FROM umbracoNode
ORDER BY id
OFFSET 0 ROWS
FETCH NEXT 10 ROWS ONLY

x

x

SELECT DISTINCT-feature

SELECT DISTINCT ContentId from cmsContentVersion ORDER BY ContentId

x

x

SELECT COUNT with DISTINCT3

SELECT COUNT(DISTINCT thumbnail) FROM cmsContentType

x

 

SELECT with LIKE in Where

SELECT *
FROM umbracoNode WHERE [text] LIKE '%st%'

x

x

SELECT with Subquery in FROM-statement.

SELECT count(contentId)
FROM (SELECT DISTINCT contentId FROM cmsContentVersion) cmsContentVersion

x

x

SELECT with LEFT OUTER JOIN

SELECT n.id, n.[text], d.dbType, d.pk FROM umbracoNode as n
LEFT OUTER JOIN cmsDataType as d ON n.id = d.nodeId

x

x

Parameter Alias declared as string

SELECT id as 'foo' FROM bar

x

 

Parameter Alias declared inline

SELECT id as foo FROM bar

X

X

SELECT with INNER JOIN Subquery in FROM

SELECT * FROM cmsTemplate as t
INNER JOIN (SELECT templateId, count(id) as total
FROM umbracoDocumentVersion WHERE published = 1
GROUP by templateId) as dv ON dv.templateId = t.nodeId

X

X

 

1. A scalar query is a query that returns one row consisting of one column.
2. Works on SQL Server 2012+, older versions need the ROW_NUMBER()
3. Another version of the query with a join in the FROM-caluse works on SQL CE: SELECT COUNT(thumbs.total) as Total FROM (SELECT DISTINCT thumbnail as total FROM cmsContentType) as thumbs

I hope that this little table is useful and please, feel free to drop a comment if you have any feedback or suggestions on things I've missed.

 

 

The yearly Umbraco festival in Sweden was hosted today in Gothenburg and I was one of the speakers. My subject was “The first Umbraco V8-site” and I tried to share some of my learnings from trying to implement a new site with the current “version” of Umbraco v8.

Presentation Usf 2018

 

You can download the slides here

This is a quite annoying problem that I sometimes hit with Resharper, some of the times the views are in the “correct” folders and sometimes when we’re using custom locations for the views.

Fortunately it can be fixed.

Use annotations to indicate where views are placed

Jetbrains ships a package of annotations that we can use to tell Resharper where our views are placed. Start by referencing the Nuget-package that contains these annotations:

Install-Package JetBrains.Annotations

Then in your solution, open the “Properties/AssemblyInfo.cs”-file and add these annotations to indicate for Resharper where you views are placed.

[assembly: AspMvcPartialViewLocationFormat(@"~\Views\Partials\{0}.cshtml")]
[assembly: AspMvcPartialViewLocationFormat(@"~\Views\MacroPartials\{0}.cshtml")]
[assembly: AspMvcViewLocationFormat(@"~\Views\{1}.cshtml")]

The example above works good with views in Umbraco CMS where some partials are placed in the "MacroPartials"-folder.

There’s three different placeholders that you can use to build the paths:

  • {0} - view name
  • {1} - controll name
  • {2} - area name

And there is also different annotations depending on what type of view we are looking for:

  • AspMvcAreaMasterLocationFormatAttribute
  • AspMvcAreaPartialViewLocationFormatAttribute
  • AspMvcAreaViewLocationFormatAttribute
  • AspMvcMasterLocationFormatAttribute
  • AspMvcPartialViewLocationFormatAttribute
  • AspMvcViewLocationFormatAttribute

Sometimes you beed to build and reload the projects for this to work.

In this post I just wanted to share some really good extensions for Visual Studio 2017 that I use on a daily basis.

File Nesting

A simple little utility that makes it possible to nest files from the UI, great for ie. web.config files with different versions for release, stage and production.

https://marketplace.visualstudio.com/items?itemName=MadsKristensen.FileNesting

https://github.com/madskristensen/FileNesting

Blog -vs -ext -file -nesting

 

Configuration Transform

This cool utility can test your configuration transform before commiting them, great to test your transforms very fast.

https://marketplace.visualstudio.com/items?itemName=GolanAvraham.ConfigurationTransform
https://github.com/golavr/ConfigurationTransform

 

Blog -vs -ext -preview _diff

 

 

One issue with the current version of configuration transform (3.2) is that it only support configuration files thats placed in the root of project, i've created a pull request that solves this: https://github.com/golavr/ConfigurationTransform/pull/6, so if you nned to work with config files outside of the root - just download and build the version with my fix and place the files in your VS-extentions folder:

For Visual Studio 2017 the path is:
%LocalAppData%\Microsoft\VisualStudio\{vs-version}\Extensions\

 

Markdown Editor

Provides a markdown editor inside Visual Studio, great when you want to edit your Github readme.md-files.

https://marketplace.visualstudio.com/items?itemName=MadsKristensen.MarkdownEditor

Vs -markdown -preview -window

 

SQLite/SQL Server Compact Toolbox

This extension brings a lot of nice features and the one that I use the most is the ability to connect to a SQL Server Compact (SQLCE) or a .sdf database.

When I work with Umbraco CMS it's very nice to have this extention installed. I usally run Umbraco with SQL Server Express but the default option in the installer is SQLCE. So this extension to Visual Studio is very handing when building packages for Umbraco and to test out something.

Using this extension we can connect to, query and modify a SQLCE database inside of Visual Studio, after install we'll find a window under "View -> Windows" where we'll find all the goodness.

Download it here:

https://marketplace.visualstudio.com/items?itemName=ErikEJ.SQLServerCompactSQLiteToolbox


 

Mapping Generator

Nice little utility that can create automatic mappings for DTOs and Domain Models or View Models, I often use it to generate a starting point and then manually change the details for properties that need it.

 

 

Download it here: https://marketplace.visualstudio.com/items?itemName=54748ff9-45fc-43c2-8ec5-cf7912bc3b84.mappinggenerator

 

 

 

I’m not sure if everyone who reads my blog knows that I’m the trainer for the official Swedish Umbraco courses. It was after CodeGarden 2013 that I was asked to help out with the education of developers and designers here in Sweden and I’ve had a lot of fun and made a lot of new friends during these events!

IMG_4170

 

Over the years I’ve had a lot of really smart people attending my courses – but I’ve never had any student regretting that they attended. It does not matter which skill-level you have before you come – there is always something new to learn and to try. A lot of people think of different courses as a way to get certified  and yes – that’s really good and very important. At the same time I really want to point out the greatest value about the courses, that’s all the knowledge  that you can take home and use in all new projects.

When I attended the trainings I’ve been working with Umbraco for about 4 years and still I decided to go to the Fundamentals training just to make sure that I haven’t missed anything important. It was some repetition but I got away after these to days with about 10 things did I did not know before – big features in the core that I’ve never used or small tips and tricks that made some tasks trivial compared to how I’ve solved them before.

This week the Norwegian developer Lars-Erik Aabech pointed out this with a nice tweet about something as simple as the “Alt Template”-feature of Umbraco.

 

A lot of experienced Umbraco developers that have not attended the trainings have probably missed out on this and on stuff like “Recursive properties”. These to thing are just small examples of stuff from the Fundamentals-training that self-thought developers never get to know.

So why does the trainings matters?

  • Fastest way to get a compact “smorgasbord” of up-to-date knowledge about Umbraco
  • Don’t miss any details or fundamentals
  • Official certification –  comforting for clients

If your in Sweden and thinks about attending a course, have e look here for the next training event!