Friday, March 4, 2016 12:25 PM umbraco
The question has been asked may times on Twitter, GitHub, Our, email, etc—a fairly common question indeed. It goes like this:
For some reason VS2015 will not recognize the types within the 'Umbraco.Web.PublishedContentModels' namespace. [...] I tried including the models.generated.cs into my project but this results into duplicate definition in runtime. Setting the build action to 'None' counteracts this, but won't fix my initial problem.
Umbraco 7.4 ships with Models Builder enabled in PureLive mode. What this means is this: at runtime model classes (ie C# code) are generated and compiled in memory and referenced when the Razor engine compiles the views (the .cshtml files). There fore, the following code will compile:
@inherit UmbracoTemplatePage<MyDocument> <div>@Model.Content.MyProperty</div>
However, the model classes do not exist outside of memory. To keep it simple, the Razor engine is the only component that knows about the models. This is what allows us to transparently re-generate and update models as you edit the content type definitions, without restarting the application. This is also what prevents any other component, such as Visual Studio, to reference the models.
By embedding the
models.generated.cs file in your project, you sure declare the models to Visual Studio... but they will be compiled once by your solution, and then a second time at runtime, resulting in a weird situation where the
MyDocument type is defined twice. The CLR usually hates that type of situation and crashes.
Visual Studio users probably want to go beyond PureLive. The easiest solution is to switch to Dll models. All you need to do is edit one application setting in
<add key="Umbraco.ModelsBuilder.ModelsMode" value="Dll" />
With that setting, models are not generated automatically anymore, and your site will probably immediately crash, because the model types do not exist. Models need to be generated explicitly by:
- Clicking 'Save and Generate' instead of 'Save' in the content type editor, or
- Clicking 'Generate' in the Models Builder dashboard (in the developers section)
When models are generated, a new Dll is created in
~/bin containing the compiled model classes. That Dll will be detected by Visual Studio, which will then know about the models and stop complaining about them in views. Voila!
It also means that the models are now visible to your entire code base, eg Surface controllers, custom code, whatever. They are, essentially, just "normal" C# types. Note that you can still inspect the models code in
~/App_Data/Models as the intermediary C# code is saved there.
In addition, because Dll models do not cause any runtime compilation, performances should improve. The only drawback of Dll models is that you need to remember to generate them whenever you modify the content types.
Why cannot we re-generate models automatically? Because generating models re-creates a Dll, and CLR applications do restart whenever their Dlls are modified. If we were to re-generate models automatically, your application would keep restarting anytime you save a content type, which can be somewhat annoying when you have a number of changes to do.
... you think it would be better anyways?
LiveDll mode, then, as it does exactly this: re-create the Dll (and restart the application) anytime a content type is changed.