Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Carlos Casalicchio 104 posts 444 karma points
    Jun 04, 2019 @ 20:15
    Carlos Casalicchio
    0

    I am not finding any documentation on how to create custom data types.

    Are custom data types not required anymore when creating Property Editors?

    I've created PropertyEditors for v7, but now it seems everything changed.

    Where's the documentation for that, pleeeeease?

  • Carlos Casalicchio 104 posts 444 karma points
    Jun 04, 2019 @ 21:45
    Carlos Casalicchio
    0

    I have been able to get it "somewhat" working, but still have no clue how to resolve this now.

    I have copied-pasted what I could find from the Umbraco source code, adjusting to my needs, and this is what I came up with.

    namespace Umbraco.Plugins.Connector.PropertyEditors
    {
        using System.Collections.Generic;
        using Umbraco.Core;
        using Umbraco.Core.Logging;
        using Umbraco.Core.Models;
        using Umbraco.Core.PropertyEditors;
    
        public class TenantPreferencesDataType : DataType
        {
            public static string NAME = "Tenant Preferences DataType";
            public TenantPreferencesDataType(IDataEditor editor, int parentId = -1) : base(editor, parentId)
            {
                base.Name = NAME;
                base.DatabaseType = ValueStorageType.Ntext;
            }
        }
        /// <summary>
        /// Represents a property editor for Tenant Preferences.
        /// </summary>
        [DataEditor(alias: "tenantPreferences", type: EditorType.PropertyValue, view: "App_Plugins\\TenantPreferences\\edit.html", name: "Tenant Preferences", Group = "Total Code", HideLabel = true, Icon = "icon-readonly", IsDeprecated = false)]
        public class TenantPreferencesPropertyEditor : DataEditor
        {
            /// <summary>
            /// Initializes a new instance of the <see cref="TenantPreferencesPropertyEditor"/> class.
            /// </summary>
            public TenantPreferencesPropertyEditor(ILogger logger)
                : base(logger)
            { }
    
            /// <inheritdoc />
            protected override IDataValueEditor CreateValueEditor() => new TenantPreferencesValueEditor(Attribute);
    
    
            /// <inheritdoc />
            protected override IConfigurationEditor CreateConfigurationEditor() => new LabelConfigurationEditor();
    
            // provides the property value editor
            internal class TenantPreferencesValueEditor : DataValueEditor
            {
                public TenantPreferencesValueEditor(DataEditorAttribute attribute)
                    : base(attribute)
                { }
    
                /// <inheritdoc />
                public override bool IsReadOnly => true;
            }
        }
    
    
        /// <summary>
        /// Represents the configuration for the label value editor.
        /// </summary>
        public class TenantPreferencesConfigurationEditor : ConfigurationEditor<TenantPreferencesConfiguration>
        {
            /// <inheritdoc />
            public override TenantPreferencesConfiguration FromConfigurationEditor(IDictionary<string, object> editorValues, TenantPreferencesConfiguration configuration)
            {
                var newConfiguration = new TenantPreferencesConfiguration();
    
                // get the value type
                // not simply deserializing Json because we want to validate the valueType
    
                if (editorValues.TryGetValue(Constants.PropertyEditors.ConfigurationKeys.DataValueType, out var valueTypeObj)
                    && valueTypeObj is string stringValue)
                {
                    if (!string.IsNullOrWhiteSpace(stringValue) && ValueTypes.IsValue(stringValue)) // validate
                        newConfiguration.ValueType = stringValue;
                }
    
                return newConfiguration;
            }
        }
        public class TenantPreferencesConfiguration : IConfigureValueType
        {
            [ConfigurationField(Constants.PropertyEditors.ConfigurationKeys.DataValueType, "Value type", "valuetype")]
            public string ValueType { get; set; } = ValueTypes.Json;
        }
    }
    

    and attempted to create the datatype and added it to a document type

    try
                {
                    var contentType = contentTypeService.Get(DOCUMENT_TYPE_ALIAS);
                    if (contentType != null)
                    {
                        var exists = dataTypeService.GetDataType(TenantPreferencesDataType.NAME) != null;
                        if (!exists)
                        {
                            DataType tenantPreferencesDataType = new TenantPreferencesDataType(new TenantPreferencesPropertyEditor(logger));
                            dataTypeService.Save(tenantPreferencesDataType);
    
                            #region Tenant Info Tab
                            PropertyType tenantPreferencesPropType = new PropertyType(tenantPreferencesDataType, "tenantPreferences")
                            {
                                Name = "Tenant Preferences",
                                Description = "Tenant Preferences for Customers",
                                Variations = ContentVariation.Nothing,
                                PropertyEditorAlias = "tenantPreferences"
                            };
                            contentType.AddPropertyType(tenantPreferencesPropType, TENANT_TAB);
                            #endregion
    
                            contentTypeService.Save(contentType);
                            ConnectorContext.AuditService.Add(AuditType.New, -1, contentType.Id, "Document Type", $"Document Type {DOCUMENT_TYPE_NAME} has been updated");
    
                        }
                    }
                }
                catch (System.Exception ex)
                {
                    logger.Error(typeof(HomeDocumentTypePhase2), ex.Message);
                    logger.Error(typeof(HomeDocumentTypePhase2), ex.StackTrace);
                }
    

    This is the error:

    Received an error from the server
    An error occured
    Error mapping types.
    
     Mapping types:
     DataTypeSave -> IDataType
     Umbraco.Web.Models.ContentEditing.DataTypeSave -> Umbraco.Core.Models.IDataType
    
     Type Map configuration:
     DataTypeSave -> IDataType
     Umbraco.Web.Models.ContentEditing.DataTypeSave -> Umbraco.Core.Models.IDataType
    
     Destination Member:
     Editor
    
    Exception Details
    AutoMapper.AutoMapperMappingException: Error mapping types.
    
     Mapping types:
     DataTypeSave -> IDataType
     Umbraco.Web.Models.ContentEditing.DataTypeSave -> Umbraco.Core.Models.IDataType
    
     Type Map configuration:
     DataTypeSave -> IDataType
     Umbraco.Web.Models.ContentEditing.DataTypeSave -> Umbraco.Core.Models.IDataType
    
     Destination Member:
     Editor
    Stacktrace
    
    at lambda_method(Closure , DataTypeSave , IDataType , ResolutionContext )
       at Umbraco.Web.Editors.DataTypeValidateAttribute.OnActionExecuting(HttpActionContext actionContext)
       at System.Web.Http.Filters.ActionFilterAttribute.OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__5.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__5.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__5.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__5.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__5.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__5.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__5.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__5.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__3.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__3.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__3.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__3.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__6.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__6.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__15.MoveNext()
    Inner Exception
    System.InvalidOperationException: Sequence contains more than one matching element
    at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
       at Umbraco.Core.PropertyEditors.PropertyEditorCollection.get_Item(String alias)
       at lambda_method(Closure , DataTypeSave , IDataType , ResolutionContext )
    
  • Mario 89 posts 653 karma points c-trib
    Jun 04, 2019 @ 22:35
    Mario
    0

    A DataType is based on a property editor and can be created from the backoffice. I don't really get what you are trying to achieve here. Do you want to create DataTyes programatically?

  • Carlos Casalicchio 104 posts 444 karma points
    Jun 04, 2019 @ 22:48
    Carlos Casalicchio
    100

    Yes, programatically.

    Previously, in version 7, it was possible to create property Editors without creating a manifest file. The Property Editor was programmatic and could be even be loaded from the Assembly, as Embedded Resources.

    See http://www.nibble.be/?p=415

    But it seems that things have changed in version 8, as I have not been able to find any documentation pointing or even suggesting a similar approach.

    I have developed the habit of creating Data Types in C#, but now that's completely obsolete!

    here is an example of the code I use in v7, and works great, creating Data Types from Assembly

    #region Data Types
            /// <summary>
            /// Creates new Custom Data Types from Reflection
            /// </summary>
            /// <returns>String Results from Creation</returns>
            public virtual string CustomDataTypes()
            {
                List<Type> types = _assembly.GetInherited<ICustomDataType>();
                if (types?.Count > 0)
                {
                    int containerId = -1;
    
                    foreach (var type in types)
                    {
                        var dataService = _applicationContext.Services.DataTypeService;
                        var propertyEditor = type.GetProperty("PropertyEditor").Value<string>();
                        var name = type.GetProperty("Name").Value<string>();
                        var exists = dataService.GetDataTypeDefinitionByName(name) != null;
    
                        if (!exists)
                        {
                            var properties = type.GetProperties();
                            var alias = type.GetProperty("Alias").Value<string>();
                            var propertiEditor = type.GetProperty("PropertyEditor").Value<string>();
                            var containerName = type.GetProperty("Container").Value<string>();
    
                            var container = _applicationContext.Services.DataTypeService.GetContainers(containerName, 1).FirstOrDefault();
    
                            if (container == null)
                            {
                                var dataTypeContainer = _applicationContext.Services.DataTypeService.CreateContainer(containerId, containerName);
    
                                if (dataTypeContainer.Success)
                                    containerId = dataTypeContainer.Result.Entity.Id;
                            }
                            else
                            {
                                containerId = container.Id;
                            }
    
                            DataTypeDefinition dataType = null;
    
                            if (!exists)
                                dataType = new DataTypeDefinition(containerId, alias);
                            else
                                dataType = dataService.GetDataTypeDefinitionByPropertyEditorAlias(alias).First() as DataTypeDefinition;
    
                            dataType.Name = name;
                            dataType.PropertyEditorAlias = propertiEditor;
    
                            Dictionary<string, object> prevalues = null;
                            if (type.GetProperty("PreValues").HasValue()) prevalues = type.GetProperty("PreValues").ValueCollection<string, object>();
                            if (prevalues != null)
                            {
                                var pDic = new Dictionary<string, PreValue>();
                                foreach (var p in prevalues) pDic.Add(p.Key, new PreValue(p.Value.ToString()));
                                dataService.SaveDataTypeAndPreValues(dataType, pDic);
                            }
                            else
                            {
                                dataService.Save(dataType);
                            }
                        }
                    }
                    return "Custom Types Created";
                }
                return "No Custom Types to be Created";
            }
    

    For version 8 I have found a workaround (though not what I want) which is to copy the physical assets into the App_Plugins folder, and then creating the DataType.

    All the code I could find in the Umbraco.Web source points to the system default data types. I could not find anything to help creating custom data types. I hope this topic gets documented soon, so I can "fix" my little hack.

    Here's the workaround for version 8

    private void UpdateHomeDocumentType()
            {
                const string editorAlias = "userPreferences";
                const string propertyAlias = "usertPreferencesProperty";
                const string dataTypeName = "User Preferences Properties";
                try
                {
                    var contentType = contentTypeService.Get(DOCUMENT_TYPE_ALIAS);
                    if (contentType != null)
                    {
                        var exists = dataTypeService.GetDataType(dataTypeName) != null;
                        if (!exists)
                        {
                            var created = Web.Composing.Current.PropertyEditors.TryGet(editorAlias, out IDataEditor editor);
                            if (created)
                            {
                                DataType tenantPreferencesDataType = new DataType(editor)
                                {
                                    Name = dataTypeName
                                };
                                dataTypeService.Save(tenantPreferencesDataType);
    
                                #region Tenant Info Tab
                                PropertyType tenantPreferencesPropType = new PropertyType(tenantPreferencesDataType, propertyAlias)
                                {
                                    Name = "Tenant Preferences",
                                    Description = "Tenant Preferences for Customers"
                                };
                                contentType.AddPropertyType(tenantPreferencesPropType, TENANT_TAB);
                                #endregion
    
                                contentTypeService.Save(contentType);
                                ConnectorContext.AuditService.Add(AuditType.New, -1, contentType.Id, "Document Type", $"Document Type {DOCUMENT_TYPE_NAME} has been updated");
                            }
                            else
                            {
                                ContentHelper.CopyPhysicalAssets(new TenantPreferencesEmbeddedResources()); // copy property editor files before trying to create the data type
                                // will need to restart the app, in order to force a refresh to attempt to create the data type again
                                throw new DataTypeNotCreatedException("In order to create the Data Type, a Reload is required");
                            }
                        }
                        else
                        {
                        }
                    }
                }
                catch (System.Exception ex)
                {
                    logger.Error(typeof(HomeDocumentTypePhase2), ex.Message);
                    logger.Error(typeof(HomeDocumentTypePhase2), ex.StackTrace);
                }
            }
    
Please Sign in or register to post replies

Write your reply to:

Draft