/// <summary> /// Gets an <see cref="Rock.Model.EntityType" /> by its name. If a match is not found, a new <see cref="Rock.Model.EntityType" /> can optionally be created. /// </summary> /// <param name="name">A <see cref="System.String" /> representing the name of the object/entity type to search for.</param> /// <param name="createIfNotFound">A <see cref="System.Boolean" /> value that indicates if a new <see cref="Rock.Model.EntityType" /> should be created if a match is not found. This value /// will be <c>true</c> if a new <see cref="Rock.Model.EntityType" /> should be created if there is not a match; otherwise <c>false</c>/</param> /// <returns></returns> public EntityType GetByName(string name, bool createIfNotFound) { var entityType = Get(name); if (entityType != null) { return(entityType); } if (createIfNotFound) { // Create a new context so type can be saved independing of current context var rockContext = new RockContext(); var entityTypeService = new EntityTypeService(rockContext); entityType = new EntityType(); entityType.Name = name; entityTypeService.Add(entityType); rockContext.SaveChanges(); // Read type using current context return(this.Get(entityType.Id)); } return(null); }
/// <summary> /// Gets the specified <see cref="Rock.Model.EntityType"/> by the object type. If a match is not found, it can optionally create a new <see cref="Rock.Model.EntityType"/> for the object. /// </summary> /// <param name="type">The <see cref="System.Type"/> to search for.</param> /// <param name="createIfNotFound">A <see cref="System.Boolean"/> value that indicates if a new <see cref="Rock.Model.EntityType"/> should be created if a match is not found. This value /// will be <c>true</c> if a new <see cref="Rock.Model.EntityType"/> should be created if there is not a match; otherwise <c>false</c>/</param> /// <param name="personAlias">A <see cref="Rock.Model.PersonAlias"/> representing the alias of the <see cref="Rock.Model.Person"/> who is searching for and possibly creating a new EntityType. This value can be /// null if the logged in person is not known (i.e. an anonymous user).</param> /// <returns>A <see cref="Rock.Model.EntityType"/> matching the provided type. If a match is not found and createIfNotFound is false this value will be null.</returns> public EntityType Get(Type type, bool createIfNotFound, PersonAlias personAlias) { var entityType = Get(type.FullName); if (entityType != null) { return(entityType); } if (createIfNotFound) { // Create a new context so type can be saved independing of current context using (var rockContext = new RockContext()) { var entityTypeService = new EntityTypeService(rockContext); entityType = new EntityType(); entityType.Name = type.FullName; entityType.FriendlyName = type.Name.SplitCase(); entityType.AssemblyName = type.AssemblyQualifiedName; entityTypeService.Add(entityType); rockContext.SaveChanges(); } // Read type using current context return(this.Get(entityType.Id)); } return(null); }
/// <summary> /// Handles the SaveClick event of the mdEdit control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> protected void mdEdit_SaveClick( object sender, EventArgs e ) { var rockContext = new RockContext(); EntityTypeService entityTypeService = new EntityTypeService( rockContext ); EntityType entityType = entityTypeService.Get( int.Parse( hfEntityTypeId.Value ) ); if ( entityType == null ) { entityType = new EntityType(); entityType.IsEntity = true; entityType.IsSecured = true; entityTypeService.Add( entityType ); } entityType.Name = tbName.Text; entityType.FriendlyName = tbFriendlyName.Text; entityType.IsCommon = cbCommon.Checked; rockContext.SaveChanges(); EntityTypeCache.Flush( entityType.Id ); hfEntityTypeId.Value = string.Empty; HideDialog(); BindGrid(); }
/// <summary> /// Gets the specified <see cref="Rock.Model.EntityType"/> by the object type. If a match is not found, it can optionally create a new <see cref="Rock.Model.EntityType"/> for the object. /// </summary> /// <param name="type">The <see cref="System.Type"/> to search for.</param> /// <param name="createIfNotFound">A <see cref="System.Boolean"/> value that indicates if a new <see cref="Rock.Model.EntityType"/> should be created if a match is not found. This value /// will be <c>true</c> if a new <see cref="Rock.Model.EntityType"/> should be created if there is not a match; otherwise <c>false</c>/</param> /// <param name="personAlias">A <see cref="Rock.Model.PersonAlias"/> representing the alias of the <see cref="Rock.Model.Person"/> who is searching for and possibly creating a new EntityType. This value can be /// null if the logged in person is not known (i.e. an anonymous user).</param> /// <returns>A <see cref="Rock.Model.EntityType"/> matching the provided type. If a match is not found and createIfNotFound is false this value will be null.</returns> public EntityType Get( Type type, bool createIfNotFound, PersonAlias personAlias ) { var entityType = Get( type.FullName ); if ( entityType != null ) { return entityType; } if ( createIfNotFound ) { // Create a new context so type can be saved independing of current context using ( var rockContext = new RockContext() ) { var EntityTypeService = new EntityTypeService( rockContext ); entityType = new EntityType(); entityType.Name = type.FullName; entityType.FriendlyName = type.Name.SplitCase(); entityType.AssemblyName = type.AssemblyQualifiedName; EntityTypeService.Add( entityType ); rockContext.SaveChanges(); } // Read type using current context return this.Get( entityType.Id ); } return null; }
/// <summary> /// Gets a list of ISecured and IEntity entities (all models) that have not yet been registered and adds them /// as an <see cref="Rock.Model.EntityType"/>. /// </summary> /// <param name="physWebAppPath">A <see cref="System.String"/> that represents the physical path of the web application</param> public static void RegisterEntityTypes( string physWebAppPath ) { var entityTypes = new Dictionary<string, EntityType>(); foreach ( var type in Rock.Reflection.FindTypes( typeof( Rock.Data.IEntity ) ) ) { var entityType = new EntityType(); entityType.Name = type.Key; entityType.FriendlyName = type.Value.Name.SplitCase(); entityType.AssemblyName = type.Value.AssemblyQualifiedName; entityType.IsEntity = !type.Value.GetCustomAttributes( typeof(System.ComponentModel.DataAnnotations.Schema.NotMappedAttribute), false ).Any(); entityType.IsSecured = false; entityTypes.Add( type.Key.ToLower(), entityType ); } foreach ( var type in Rock.Reflection.FindTypes( typeof( Rock.Security.ISecured ) ) ) { string key = type.Key.ToLower(); if ( entityTypes.ContainsKey( key ) ) { entityTypes[key].IsSecured = true; } else { var entityType = new EntityType(); entityType.Name = type.Key; entityType.FriendlyName = type.Value.Name.SplitCase(); entityType.AssemblyName = type.Value.AssemblyQualifiedName; entityType.IsEntity = false; entityType.IsSecured = true; entityTypes.Add( key, entityType ); } } using ( var rockContext = new RockContext() ) { var entityTypeService = new EntityTypeService( rockContext ); // Find any existing EntityTypes marked as an entity or secured that are no longer an entity or secured foreach ( var oldEntityType in entityTypeService.Queryable() .Where( e => e.IsEntity || e.IsSecured ) .ToList() ) { if ( !entityTypes.Keys.Contains( oldEntityType.Name.ToLower() ) ) { oldEntityType.IsSecured = false; oldEntityType.IsEntity = false; oldEntityType.AssemblyName = null; EntityTypeCache.Flush( oldEntityType.Id ); } } // Update any existing entities foreach ( var existingEntityType in entityTypeService.Queryable() .Where( e => entityTypes.Keys.Contains( e.Name ) ) .ToList() ) { var key = existingEntityType.Name.ToLower(); var entityType = entityTypes[key]; if ( existingEntityType.Name != entityType.Name || existingEntityType.IsEntity != entityType.IsEntity || existingEntityType.IsSecured != entityType.IsSecured || existingEntityType.FriendlyName != ( existingEntityType.FriendlyName ?? entityType.FriendlyName ) || existingEntityType.AssemblyName != entityType.AssemblyName ) { existingEntityType.Name = entityType.Name; existingEntityType.IsEntity = entityType.IsEntity; existingEntityType.IsSecured = entityType.IsSecured; existingEntityType.FriendlyName = existingEntityType.FriendlyName ?? entityType.FriendlyName; existingEntityType.AssemblyName = entityType.AssemblyName; EntityTypeCache.Flush( existingEntityType.Id ); } entityTypes.Remove( key ); } // Add the newly discovered entities foreach ( var entityTypeInfo in entityTypes ) { // Don't add the EntityType entity as it will probably have been automatically // added by the audit on a previous save in this method. if ( entityTypeInfo.Value.Name != "Rock.Model.EntityType" ) { entityTypeService.Add( entityTypeInfo.Value ); } } rockContext.SaveChanges(); // make sure the EntityTypeCache is synced up with any changes that were made foreach (var entityTypeModel in entityTypeService.Queryable()) { EntityTypeCache.Read( entityTypeModel ); } } }
/// <summary> /// Gets an <see cref="Rock.Model.EntityType" /> by its name. If a match is not found, a new <see cref="Rock.Model.EntityType" /> can optionally be created. /// </summary> /// <param name="name">A <see cref="System.String" /> representing the name of the object/entity type to search for.</param> /// <param name="createIfNotFound">A <see cref="System.Boolean" /> value that indicates if a new <see cref="Rock.Model.EntityType" /> should be created if a match is not found. This value /// will be <c>true</c> if a new <see cref="Rock.Model.EntityType" /> should be created if there is not a match; otherwise <c>false</c>/</param> /// <returns></returns> public EntityType Get( string name, bool createIfNotFound ) { var entityType = Get( name ); if ( entityType != null ) { return entityType; } if ( createIfNotFound ) { // Create a new context so type can be saved independing of current context var rockContext = new RockContext(); var EntityTypeService = new EntityTypeService( rockContext ); entityType = new EntityType(); entityType.Name = name; EntityTypeService.Add( entityType ); rockContext.SaveChanges(); // Read type using current context return this.Get( entityType.Id ); } return null; }
/// <summary> /// Uses Reflection to find all IEntity entities (all models), ISecured Types (could be a model or a component), and IRockBlockTypes. /// Then ensures that the <seealso cref="Rock.Model.EntityType" /> table is synced up to match. /// </summary> public static void RegisterEntityTypes() { List <Type> reflectedTypes = new List <Type>(); // we'll auto-register anything that implements IEntity, ISecured or IRockBlockType reflectedTypes.AddRange(Rock.Reflection.FindTypes(typeof(Rock.Data.IEntity)).Values); reflectedTypes.AddRange(Rock.Reflection.FindTypes(typeof(Rock.Security.ISecured)).Values); reflectedTypes.AddRange(Rock.Reflection.FindTypes(typeof(Rock.Blocks.IRockBlockType)).Values); // do a distinct since some of the types implement both IEntity and ISecured reflectedTypes = reflectedTypes.Distinct().OrderBy(a => a.FullName).ToList(); Dictionary <string, EntityType> entityTypesFromReflection = new Dictionary <string, EntityType>(StringComparer.OrdinalIgnoreCase); foreach (var reflectedType in reflectedTypes) { var entityType = new EntityType(); entityType.Name = reflectedType.FullName; entityType.FriendlyName = reflectedType.Name.SplitCase(); entityType.AssemblyName = reflectedType.AssemblyQualifiedName; if (typeof(IEntity).IsAssignableFrom(reflectedType)) { entityType.IsEntity = reflectedType.GetCustomAttribute <System.ComponentModel.DataAnnotations.Schema.NotMappedAttribute>() == null; } else { entityType.IsEntity = false; } entityType.IsSecured = typeof(Rock.Security.ISecured).IsAssignableFrom(reflectedType); entityTypesFromReflection.AddOrIgnore(reflectedType.FullName, entityType); } ; using (var rockContext = new RockContext()) { var entityTypeService = new EntityTypeService(rockContext); var reflectedTypeNames = reflectedTypes.Select(a => a.FullName).ToArray(); // Get all the EntityType records from the Database without filtering them (we'll have to deal with them all) // Then we'll split them into a list of ones that don't exist and ones that still exist var entityTypeInDatabaseList = entityTypeService.Queryable().ToList(); // Find any existing self-discovered EntityType records that no longer exist in reflectedTypes // but have C# narrow it down to ones that aren't in the reflectedTypeNames list var reflectedEntityTypesThatNoLongerExist = entityTypeInDatabaseList .Where(e => !string.IsNullOrEmpty(e.AssemblyName)) .ToList() .Where(e => !reflectedTypeNames.Contains(e.Name)) .OrderBy(a => a.Name) .ToList(); // clean up entitytypes that don't have an Assembly, but somehow have IsEntity or IsSecured set foreach (var entityTypesWithoutAssembliesButIsEntity in entityTypeInDatabaseList.Where(e => string.IsNullOrEmpty(e.AssemblyName) && (e.IsEntity || e.IsSecured))) { if (entityTypesWithoutAssembliesButIsEntity.AssemblyName.IsNullOrWhiteSpace()) { entityTypesWithoutAssembliesButIsEntity.IsEntity = false; entityTypesWithoutAssembliesButIsEntity.IsSecured = false; } } foreach (var oldEntityType in reflectedEntityTypesThatNoLongerExist) { Type foundType = null; // if this isn't one of the EntityTypes that we self-register, // see if it was manually registered first (with EntityTypeCache.Get(Type type, bool createIfNotExists)) try { foundType = Type.GetType(oldEntityType.AssemblyName, false); } catch { /* 2020-05-22 MDP * GetType (string typeName, bool throwOnError) can throw exceptions even if throwOnError is false! * see https://docs.microsoft.com/en-us/dotnet/api/system.type.gettype?view=netframework-4.5.2#System_Type_GetType_System_String_System_Boolean_ * * so, if this happens, we'll ignore any error it returns in those cases too */ } if (foundType == null) { // it was manually registered but we can't create a Type from it // so we'll update the EntityType.AssemblyName to null // and set IsSecured and IsEntity to False (since a NULL type doesn't implement ISecured or IEntity) oldEntityType.AssemblyName = null; oldEntityType.IsSecured = false; oldEntityType.IsEntity = false; } } // Now get the entityType records that are still in the list of types we found thru reflection // but we'll have C# narrow it down to ones that aren't in the reflectedTypeNames list var reflectedEntityTypesThatStillExist = entityTypeInDatabaseList .Where(e => reflectedTypeNames.Contains(e.Name)) .ToList(); // Update any existing entities foreach (var existingEntityType in reflectedEntityTypesThatStillExist) { var entityTypeFromReflection = entityTypesFromReflection.GetValueOrNull(existingEntityType.Name); if (entityTypeFromReflection == null) { continue; } if (existingEntityType.Name != entityTypeFromReflection.Name || existingEntityType.IsEntity != entityTypeFromReflection.IsEntity || existingEntityType.IsSecured != entityTypeFromReflection.IsSecured || existingEntityType.FriendlyName != (existingEntityType.FriendlyName ?? entityTypeFromReflection.FriendlyName) || existingEntityType.AssemblyName != entityTypeFromReflection.AssemblyName) { existingEntityType.Name = entityTypeFromReflection.Name; existingEntityType.IsEntity = entityTypeFromReflection.IsEntity; existingEntityType.IsSecured = entityTypeFromReflection.IsSecured; existingEntityType.FriendlyName = existingEntityType.FriendlyName ?? entityTypeFromReflection.FriendlyName; existingEntityType.AssemblyName = entityTypeFromReflection.AssemblyName; } entityTypesFromReflection.Remove(existingEntityType.Name); } // Add the newly discovered entities foreach (var entityType in entityTypesFromReflection.Values) { // Don't add the EntityType entity as it will probably have been automatically // added by the audit on a previous save in this method. if (entityType.Name != "Rock.Model.EntityType") { entityTypeService.Add(entityType); } } rockContext.SaveChanges(); // make sure the EntityTypeCache is synced up with any changes that were made foreach (var entityTypeModel in entityTypeService.Queryable().AsNoTracking()) { EntityTypeCache.Get(entityTypeModel); } } }
/// <summary> /// Gets a list of ISecured and IEntity entities (all models) that have not yet been registered and adds them /// as an <see cref="Rock.Model.EntityType"/>. /// </summary> /// <param name="physWebAppPath">A <see cref="System.String"/> that represents the physical path of the web application</param> public static void RegisterEntityTypes(string physWebAppPath) { var entityTypes = new Dictionary <string, EntityType>(); foreach (var type in Rock.Reflection.FindTypes(typeof(Rock.Data.IEntity))) { var entityType = new EntityType(); entityType.Name = type.Key; entityType.FriendlyName = type.Value.Name.SplitCase(); entityType.AssemblyName = type.Value.AssemblyQualifiedName; entityType.IsEntity = !type.Value.GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.Schema.NotMappedAttribute), false).Any(); entityType.IsSecured = false; entityTypes.Add(type.Key.ToLower(), entityType); } foreach (var type in Rock.Reflection.FindTypes(typeof(Rock.Security.ISecured))) { string key = type.Key.ToLower(); if (entityTypes.ContainsKey(key)) { entityTypes[key].IsSecured = true; } else { var entityType = new EntityType(); entityType.Name = type.Key; entityType.FriendlyName = type.Value.Name.SplitCase(); entityType.AssemblyName = type.Value.AssemblyQualifiedName; entityType.IsEntity = false; entityType.IsSecured = true; entityTypes.Add(key, entityType); } } using (var rockContext = new RockContext()) { var entityTypeService = new EntityTypeService(rockContext); // Find any existing EntityTypes marked as an entity or secured that are no longer an entity or secured foreach (var oldEntityType in entityTypeService.Queryable() .Where(e => e.IsEntity || e.IsSecured) .ToList()) { if (!entityTypes.Keys.Contains(oldEntityType.Name.ToLower())) { oldEntityType.IsSecured = false; oldEntityType.IsEntity = false; oldEntityType.AssemblyName = null; EntityTypeCache.Flush(oldEntityType.Id); } } // Update any existing entities foreach (var existingEntityType in entityTypeService.Queryable() .Where(e => entityTypes.Keys.Contains(e.Name)) .ToList()) { var key = existingEntityType.Name.ToLower(); var entityType = entityTypes[key]; if (existingEntityType.Name != entityType.Name || existingEntityType.IsEntity != entityType.IsEntity || existingEntityType.IsSecured != entityType.IsSecured || existingEntityType.FriendlyName != (existingEntityType.FriendlyName ?? entityType.FriendlyName) || existingEntityType.AssemblyName != entityType.AssemblyName) { existingEntityType.Name = entityType.Name; existingEntityType.IsEntity = entityType.IsEntity; existingEntityType.IsSecured = entityType.IsSecured; existingEntityType.FriendlyName = existingEntityType.FriendlyName ?? entityType.FriendlyName; existingEntityType.AssemblyName = entityType.AssemblyName; EntityTypeCache.Flush(existingEntityType.Id); } entityTypes.Remove(key); } // Add the newly discovered entities foreach (var entityTypeInfo in entityTypes) { // Don't add the EntityType entity as it will probably have been automatically // added by the audit on a previous save in this method. if (entityTypeInfo.Value.Name != "Rock.Model.EntityType") { entityTypeService.Add(entityTypeInfo.Value); } } rockContext.SaveChanges(); // make sure the EntityTypeCache is synced up with any changes that were made foreach (var entityTypeModel in entityTypeService.Queryable()) { EntityTypeCache.Read(entityTypeModel); } } }