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 )
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?
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.
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);
}
}
This is the code to create a data type in Umbraco v11
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services;
using UmbracoConstants = Umbraco.Cms.Core.Constants;
namespace SplatDev.Umbraco.Plugins.USStates
{
public class USStatesDataType
{
private readonly IServiceScopeFactory _scopeFactory;
private const string DataTypeName = "US States and Canada Districts";
public USStatesDataType(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
public void Install()
{
using var scope = _scopeFactory.CreateScope();
var dataTypeService = scope.ServiceProvider.GetRequiredService<IDataTypeService>();
if (dataTypeService.GetDataType(DataTypeName) is not null) return;
var propertyEditorCollection = scope.ServiceProvider.GetRequiredService<PropertyEditorCollection>();
var serializer = scope.ServiceProvider.GetRequiredService<IConfigurationEditorJsonSerializer>();
propertyEditorCollection.TryGet(UmbracoConstants.PropertyEditors.Aliases.DropDownListFlexible, out IDataEditor? editor);
int counter = 0;
dataTypeService.Save(new DataType(editor, serializer)
{
DatabaseType = ValueStorageType.Ntext,
CreateDate = DateTime.Now,
CreatorId = -1,
Name = DataTypeName,
Configuration = new DropDownFlexibleConfiguration()
{
Multiple = false,
Items = new List<ValueListConfiguration.ValueListItem> {
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "ALABAMA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "ALASKA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "ALBERTA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "AMERICAN SAMOA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "ARIZONA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "ARKANSAS" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "BRITISH COLUMBIA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "CALIFORNIA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "CAROLINE ISLANDS" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "COLORADO" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "CONNETICUT" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "DELAWARE" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "DISTRICT OF COLUMBIA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "FEDERATED STATE" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "FLORIDA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "GEORGIA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "GUAM" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "HAWAII" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "IDOHA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "ILLINOIS" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "INDIANA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "IOWA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "KANSAS" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "KENTUCKY" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "LOUSIANA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "MAINE" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "MANITOBA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "MARIANA ISLANDS" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "MARSHALL ISLANDS" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "MARYLAND" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "MASSACHUSETTS" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "MICHIGAN" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "MINNESOTA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "MISSISSIPPI" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "MISSOURI" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "MONTANA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "NEBRASKA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "NEVADA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "NEW BRUNSWICK" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "NEW HAMPSHIRE" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "NEW JERSEY" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "NEW MEXICO" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "NEW YORK" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "NEWFOUNDLAND" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "NORTH CAROLINA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "NORTH DAKOTA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "NORTHWEST TERRITORIES" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "NOVA SCOTIA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "NUNAVUT" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "OHIO" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "OKLAHOMA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "ONTARIO" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "OREGON" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "PENNSYLVANIA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "PRINCE EDWARD ISLAND" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "PUERTO RICO" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "QUEBEC" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "RHODE ISLAND" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "SASKATCHEWAN" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "SOUTH CAROLINA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "SOUTH DAKOTA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "TENNESSEE" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "TEXAS" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "UTAH" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "VERMONT" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "VIRGIN ISLANDS" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "VIRGINIA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "WASHINGTON" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "WEST VIRGINIA" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "WISCONSIN" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "WYOMING" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "YUKON TERRITORY" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "ARMED FORCES - EUROPE" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "ARMED FORCES - AMERICAS" },
new ValueListConfiguration.ValueListItem { Id = ++counter, Value = "ARMED FORCES - PACIFIC" }
}
}
});
}
}
}
And this is the Composer
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.Composing;
namespace SplatDev.Umbraco.Plugins.USStates
{
public class DataTypeComposer : ComponentComposer<DataTypeComponent> { }
public class DataTypeComponent : IComponent
{
private readonly IServiceScopeFactory _scopeFactory;
public DataTypeComponent(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
public void Initialize()
{
new USStatesDataType(_scopeFactory).Install();
}
public void Terminate()
{
}
}
}
Creating Custom Data Type
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?
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.
and attempted to create the datatype and added it to a document type
This is the error:
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?
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
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
This is the code to create a data type in Umbraco v11
And this is the Composer
Thanks Carlos, you have literally saved my life with this update!
Thanks! I never would have worked out the IScopeFactory stuff without this post
is working on a reply...