Skip to content

Instantly share code, notes, and snippets.

@agrath
Last active March 26, 2018 10:49
Show Gist options
  • Save agrath/62313e7c0b021ebeb2277d076ca45354 to your computer and use it in GitHub Desktop.
Save agrath/62313e7c0b021ebeb2277d076ca45354 to your computer and use it in GitHub Desktop.
An example of dynamically generated strong properties for Umbraco ModelsBuilder
//A PublishEventHandler catches the DataTypeService.Saved method as a developer workflow entry point;
//When the data type is saved this kicks off the generation and writes a model to our models folder
//This could be app_code if you don't use VS to build your solution, but we generate our ModelsBuilder models
//into a class which is then built as part of the solution
internal class PublishEventHandler : ApplicationEventHandler
{
public const string FileSuffix = ".smartpropertytype.cs";
protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
DataTypeService.Saved += DataTypeService_Saved;
}
private void DataTypeService_Saved(IDataTypeService sender, global::Umbraco.Core.Events.SaveEventArgs<global::Umbraco.Core.Models.IDataTypeDefinition> e)
{
if (e.SavedEntities.Any(entity => entity.PropertyEditorAlias == "CONTROLALIAS" || entity.PropertyEditorAlias == "OTHERCONTROL"))
{
//GENERATE THE MODEL FILE (OVERWRITE .CS IF EXISTS)
}
}
}
//Our config for ModelsBuilder
/*
<add key="Umbraco.ModelsBuilder.Enable" value="true" />
<add key="Umbraco.ModelsBuilder.ModelsMode" value="AppData" />
<add key="Umbraco.ModelsBuilder.ModelsNamespace" value="Project.ContentModels" />
<add key="Umbraco.ModelsBuilder.LanguageVersion" value="CSharp6" />
<add key="Umbraco.ModelsBuilder.ModelsDirectory" value="~/../Project.ContentModels/Generated" />
<add key="Umbraco.ModelsBuilder.AcceptUnsafeModelsDirectory" value="true" />
*/
//The normal Umbraco ModelsBuilder generates models like this, so we don't and can't alter this behaviour
//So we let ModelsBuilder generate its own models and write them
//Here is a sample of a minified generated model for homepage, this should be familiar if you've used ModelsBuilder
namespace Project.ContentModels
{
/// <summary>Homepage</summary>
[PublishedContentModel("homepage")]
public partial class Homepage : PublishedContentModel, IPageHeader
{
#pragma warning disable 0109 // new is redundant
public new const string ModelTypeAlias = "homepage";
public new const PublishedItemType ModelItemType = PublishedItemType.Content;
#pragma warning restore 0109
public Homepage(IPublishedContent content)
: base(content)
{ }
#pragma warning disable 0109 // new is redundant
public new static PublishedContentType GetModelContentType()
{
return PublishedContentType.Get(ModelItemType, ModelTypeAlias);
}
#pragma warning restore 0109
public static PublishedPropertyType GetModelPropertyType<TValue>(Expression<Func<Homepage, TValue>> selector)
{
return PublishedContentModelUtility.GetModelPropertyType(GetModelContentType(), selector);
}
///<summary>
/// Content
///</summary>
[ImplementPropertyType("propertyAlias")]
public IHtmlString PropertyAlias
{
get { return this.GetPropertyValue<IHtmlString>("propertyAlias"); }
}
}
}
//As a developer, when you are editing a data type which represents something you want a custom model for
//e.g. when you would normally generate a dynamic or jObject property but would really prefer a strong class
//you go and save the data type, then the event is caught by the handler above and this generates an additional model class
//file for your custom content
//Here's an example of one of those (faked for this gist)
public class StrongJsonDeserializedModel
{
public StrongJsonDeserializedModel(string json)
{
var that = JsonConvert.DeserializeObject<StrongJsonDeserializedModel>(json);
this.X = that.X;
this.Y = that.Y;
}
public int X {get;set;}
public int Y {get;set;}
}
//This is an additional Homepage partial class that is also generated by our datatype save event
//it implements the property propetyAlias
//https://our.umbraco.org/Documentation/reference/templating/Modelsbuilder/Control-Generation#implement-property-type
//As per Indicates that a property implements a property type with a given alias. The attribute must decorate the
//corresponding property type property. Use when alias and property name do not match.
//This will cause the property propertyAlias to not be generated, since you already implement it as StrongPropertyAlias.
public partial class Homepage
{
[ImplementPropertyType("propertyAlias")]
public StrongJsonDeserializedModel StrongPropertyAlias { get { return new StrongJsonDeserializedModel(this.GetPropertyValue<string>("propertyAlias")); } }
}
//now from your view:
@inherits Umbraco.Web.Mvc.UmbracoTemplatePage<Homepage>
@{
Layout = "Master.cshtml";
}
//@Model.Content.StrongPropertyAlias => StrongJsonDeserializedModel
@Model.Content.StrongPropertyAlias.X
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment