Add a Dynamic Content selector to a User Profile

For a project I was working on I needed to create a relation between Projects (which is an entity from my Sitefinity Module Builder) and a Sitefinity User. There are a couple of ways to do this and I choose one that fits the actual need of my client.

  • April 15, 2019

Introduction

For a project I was working on I needed to create a relation between Projects (which is an entity from my Sitefinity Module Builder) and a Sitefinity User. There are a couple of ways to do this and I choose one that fits the actual need of my client.

What do we need?

  1. We first need a Dynamic Module, created with the Module Builder that holds project information. In my case this was a really simple entity. Title, Date, Documents.
  2. Second we to create a selector field, which allows us to pick one or more projects. The results of this selector are returned as a Guid array.
  3. Last thing we need is a new custom field in our user profile which will hold the Projects that we select through our selector.

The problem

Sounds fairly simple, but the thing is that through the Sitefinity interface it is currently not possible to add custom fields of type Guid[] (a Guid array). So even if we can enter a custom field like our project selector, created by Sitefinity Thunder, it wouldn't work, since it expects that the results are stored inside this field of type Guid[].

The solution

At this time we can't do other then do this through code, by using the Sitefinity API's. We can create a new custom field of type Guid[] and then edit all the views to add the project selector. These views are for example when you create a user, edit a user etc.

The following method helps us create a new field and the related selector. It is a generic methods, so you can use it for other field elements also.

/// <summary>
/// Register a custom field for a specific User Profile
/// </summary>
/// <typeparam name="TE"></typeparam>
/// <param name="userProfileType"></param>
/// <param name="fieldName"></param>
/// <example></example>
public static void RegisterFieldForUserProfile<TE> (string userProfileType, string fieldName)
where TE : FieldControlDefinitionElement { // Check if the field is not already present for this content type UserProfileManager.GetManager (); var itemClrType = TypeResolutionService.ResolveType (userProfileType); // Specify the persistent filed CLR type (e.g. String, Guid[], ContentLink). // Please ensure your custom field has been properly implemented to work with that CLR type var persistentFieldType = typeof (Guid[]); var itemType = itemClrType.FullName; // Check to see if the field exists var fieldExists = GetMetaFieldsForType (itemType).SingleOrDefault (f => f.FieldName == fieldName) != null; if (fieldExists) return; // Add the metafield that will hold the data to the profile App.WorkWith () .DynamicData () .Type (itemClrType) .Field () .TryCreateNew (fieldName, persistentFieldType) .SaveChanges (true); // Get correct module configuration depending on item type var manager = ConfigManager.GetManager (); // Suppress the security var suppressSecurityChecks = manager.Provider.SuppressSecurityChecks; manager.Provider.SuppressSecurityChecks = true; // Get Backend views(e.g. Edit, Create) configuration var section = Config.Get<ContentViewConfig> (); var profileTypeName = userProfileType.Replace ("Telerik.Sitefinity.Security.Model.", ""); var definitionName = "ProfileType_" + profileTypeName; var backendSection = section.ContentViewControls[definitionName]; var views = backendSection.ViewsConfig.Values.Where (v => v.ViewType == typeof (DetailFormView)); foreach (DetailFormViewElement view in views) { // If there are no custom fields added before, the new field will be placed int he CustomFieldsSection var sectionToInsert = CustomFieldsContext.GetSection (view, CustomFieldsContext.customFieldsSectionName, itemType); var fieldConfigElementType = TypeResolutionService.ResolveType (typeof (TE).FullName); // Create a new instance of our field configuration in the current view configuration var newElement = Activator.CreateInstance (fieldConfigElementType, new object[] { sectionToInsert.Fields }) as TE; // Populate custom field values if (newElement == null) continue; newElement.DataFieldName = fieldName; newElement.FieldName = fieldName; newElement.Title = fieldName; newElement.DisplayMode = FieldDisplayMode.Write; sectionToInsert.Fields.Add (newElement); } // Save and restart the application manager.SaveSection (section); manager.Provider.SuppressSecurityChecks = suppressSecurityChecks; SystemManager.RestartApplication (true);
}

We also use this helper method to check if the field exists  

/// <summary>
/// Returns an IList of Meta Fields for the specified type
/// </summary>
public static IList<MetaField> GetMetaFieldsForType (string type) { var existingType = TypeResolutionService.ResolveType (type); var existingClassName = existingType.Name; var existingNamespace = existingType.Namespace; var metaType = MetadataManager.GetManager ().GetMetaTypes ().SingleOrDefault (dt => dt.ClassName == existingClassName && dt.Namespace == existingNamespace); if (metaType == null) return null; var fields = metaType .Fields; return fields;
}

We can use this code inside a simple .aspx page with a button to execute, or add it to an e.g. helper library.

To call the method, it will look something like this:

RegisterFieldForUserProfile<ProjectSelectorElement>("Telerik.Sitefinity.Security.Model.SitefinityProfile", "Projects");

So when this is executed, the new field is created and we now have our project selector added to the user profile.

So there we have our solution. Thanks to Atanas Valchev  for helping me with this.

Check out this weblog or sitefinity.com if you need more help and resources.


Image Description

Daniel Plomp

Entrepreneur, Senior Software Engineer .NET, Sitefinity Solution specialist, Orchard CMS enthusiast, Product Owner

All Author Posts

Got another minute? Check out:

Image Description

Call us

+31 (0) 36-2000196
Image Description

Email us

mail@zimplerconsulting.com
Image Description

Address

Grote Beer 57, 3893 DJ Zeewolde
NLThe Netherlands

Please sign in

Signin to manage your account.

Do not have an account? Signup

OR