
Models Builder is an excellent tool in Umbraco for generating stongly typed models. When setting the ModelsMode to SourceCodeAuto or SourceCodeManual, models will be generated either when a Document type is saved or when we hit the Generate Models button in backoffice. At Webmind, we often use SourceCodeManual to get full control and the freedom to choose exactly when our models are generated.
Generated models are to be considered source code as any other source code so it makes sense to follow the left-to-right approach of deployment, i.e. let the changes move through the environments from local development, to Development on cloud, to Staging on cloud, and finally to Live on cloud.
For the same reasons that we do not make changes to code on any other environment than in our local environments, we shouldn't be generating models on any of the cloud environments.
Therefore, the ModelsMode should not be set to SourceCodeManual on cloud but instead have the value "Nothing" on all cloud environments. If we do that, we ensure that models are generated in local environments and in local environments only, and then pushed trough the deploy chain in the same way as all other code is.
When we are to configure this behavior, there are a few things to keep in mind.
Every environment has a programmatic name. Umbraco Cloud follows the conventions of ASPNET.Core and thus the EnvironmentNames of the cloud environments are
Cloud environment display name |
Programmatic Environment Name |
Development |
Development |
Staging |
Staging |
Live |
Production |
These names are used in the ASPNET.Core framework in multiple ways. We get methods such as WebApplicationBuilder.Environment.IsDevelopment() that returns true only if the environment name is Environments.Development, a method often used in Program.cs.
We have different appsettings files that each targets a specific environment based on its name, namely appsettings.Development.json, appsettings.Staging.json, and appsettings.Production.json.
An often recommended approach is to use these appsettings files to allow for different configurations for different environments. We could do "ModelsMode": "SourceCodeManual" in appsettings.Development.json and "ModelsMode": "Nothing" in appsettings.Production.json for example to achieve different behavior from Models Builder based on the environment name.
Here's the crux though - what's your local development environment called? You guessed it: It's Development. So, the Development environment on Cloud shares the same name as your local environment. This is stated in your launchSettings.json file where you can find two profiles, one for starting your application with dotnet run, and one for starting your application from inside Visual Studio with IIS Express. Both these profiles have the environment variable ASPNETCORE_ENVIRONMENT set to "Development". This is what makes your application choose to read configurations specifically from the appsettings.Development.json file when running locally.
A common solution to the problem of having two of the environments share the same name is to rename your local environment to something like "ASPNETCORE_ENVIRONMENT": "Local" in launchSettings.json and then create an additional appsettings file called appsettings.Local.json. This does infact enable different configurations for your local environment and the cloud Development environment as they no longer share the same name. However, it also breaks the built in functionality of ASPNET.Core, like the IsDevelopment() method that will now all of a sudden return false when you are running locally, since your local environment is no longer called "Development".
It should be considered better practice to instead place your local ModelsBuilder configurations not in appsettings but in launchSettings.json, like so:
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"Umbraco__CMS__ModelsBuilder__ModelsMode": "SourceCodeManual",
"Umbraco__CMS__ModelsBuilder__FlagOutOfDateModels": "true",
"Umbraco__CMS__ModelsBuilder__ModelsNamespace": "Umbraco.Cms.Web.Common.PublishedModels",
"Umbraco__CMS__ModelsBuilder__ModelsDirectory": "~/../TheNextAmazingWebProject.PublishedModels/Models",
"Umbraco__CMS__ModelsBuilder__AcceptUnsafeModelsDirectory": "true",
"Umbraco__CMS__ModelsBuilder__DebugLevel": "1"
}
As launchSettings.json is only used when running your project from Visual Studio and/or via dotnet run in the CLI, this ensures that the configurations are only run in the local development environment and preserves the EnvironmentName of the local environment as "Development" at the same time, thus not disabling or changing any of the program logic.
The two environments will still share the same name but the application will read its Models Builder configurations from launchSettings.json when running locally, so we will have the ability to generate models from backoffice that can be pushed through the deploy chain along with the rest of our code.
When we've modified our launchSettings.json, we can get rid of all Models Builder configurations in any of the three appsettings.{environment}.json files and place the only Models Builder configuration we need only in appsettings.json, namely:
"ModelsBuilder": {
"ModelsMode": "Nothing"
}
The result of this is that the application will read its Models Builder configurations from appsettings.json for all three environments on cloud, as there is no environment specific configurations in any of the environment specific appsettings files. The Generate Models button will not be present on any of the cloud environments.
So, we get a single Models Builder configuration for all cloud environments, no need to create an additional custom appsettings file, and we are not renaming our local environment thus not breaking any of the pre-existing ASPNET.Core functionality.
I hope that made sense. If we got anything wrong, or if you disagree, or have other experiences - feel free to reach out. The best way to learn is together. Thanks for reading.
Kristoffer Sundberg Billestedt