public async Task <ActionResult> ReleaseMetadata(ReleaseMetadataRequest request) { if (!_permissionService.IsAllowed(new ActionRequestInfo(HttpContext, _implementationContainer, null, ActionTypeEnum.ManageMetadata))) { return(Unauthorized()); } var appInstance = await _dbContext.AppInstances.SingleAsync(X => X.Id == request.AppInstanceId); var appType = await _dbContext.AppTypes.SingleAsync(x => x.Id == appInstance.AppTypeId); var bundle = await MetadataBundle.FromDbWithoutNavigations(_dbContext, appType.Id, appInstance.Id); var json = JsonConvert.SerializeObject(bundle); var zipped = TextHelper.Zip(json); var release = new MetadataRelease { AppTypeId = appType.Id, CreatedByUserId = 0, //Todo: How to get this value? ReleaseTime = DateTime.UtcNow, MetadataSnapshotText = json, Version = request.Version, VersionCode = request.VersionCode }; await _dbContext.MetadataReleases.AddAsync(release); if (request.SetAsInstanceMetadata) { appInstance.MetadataRelease = release; } await _dbContext.SaveChangesAsync(); return(Ok()); }
public async Task <ActionResult <MetadataValidationResponse> > GenerateCode() { if (!_permissionService.IsAllowed(new ActionRequestInfo(HttpContext, _implementationContainer, null, ActionTypeEnum.ManageMetadata))) { return(Unauthorized()); } var bundle = await MetadataBundle.FromDbWithoutNavigations(_dbContext , _implementationContainer.InstanceInfo.AppTypeId, _implementationContainer.InstanceInfo.AppInstanceId); bundle.FixupRelationships(); var metadataCache = new MetadataCache(bundle); var errorList = await GenerateCodeValidation(); var result = new MetadataValidationResponse(); if (errorList.Value?.Success != true) { return(errorList); } var(succeeded, diagnostics) = await _assemblyGenerator.GenerateAssembly(metadataCache, _implementationContainer.InstanceInfo , _globalConfiguration.ImplementationsDirectory, _implementationContainer.InstanceInfo.InstanceName); if (!succeeded) { result.Errors.AddRange(diagnostics.Select(x => x.Message)); result.Success = false; return(result); } result.Success = true; return(result); }
private void LoadPropertyGeneralUsageCategories(MetadataBundle bundle) { _propertyGeneralUsageCategories = bundle.PropertyGeneralUsageCategories.ToDictionary ( x => x.Id, x => new PropertyGeneralUsageCategoryStruct { PropertyGeneralUsageCategoryId = x.Id, Name = x.Name } ); }
private void LoadEntityGeneralUsageCategories(MetadataBundle bundle) { _entityGeneralUsageCategories = bundle.EntityTypeGeneralUsageCategories.ToDictionary ( x => x.Id, x => new EntityGeneralUsageCategoryStruct { EntityGeneralUsageCategoryId = x.Id, Name = x.Name } ); }
public MetadataModel(MetadataBundle bundle) { AdditionalBehaviors = bundle.AdditionalBehaviors.ToDictionary(x => x.Name, x => new AdditionalBehaviorMetadata { Definition = x.Definition, Name = x.Name }); PropertyDefaults = bundle.PropertyFacetDefaultValues .GroupBy(x => x.GeneralUsageCategory.Name) .Select(x => new PropertyGeneralUsageCategory { Name = x.Key, Defaults = x .Select(y => PropertyFacet.Create(y)) .ToDictionary(y => y.Name, y => y) }).ToDictionary(x => x.Name, x => x as IPropertyGeneralUsageCategory); EntityTypes = bundle.EntityTypes.Select(x => new EntityMetadata { Name = x.Name, SchemaName = x.SchemaName, EntityGeneralUsageCategoryId = x.GeneralUsageCategoryId, SingularTitle = x.SingularTitle, PluralTitle = x.PluralTitle, DisplayNamePath = x.DisplayNamePath, CodePath = x.CodePath, PrimaryKeyPath = x.Properties?.FirstOrDefault(p => p.GeneralUsageCategoryId == 2)?.Name, //TODO: Unsafe Properties = x.Properties?.Select(p => new PropertyMetadata { Name = p.Name, GeneralUsage = p.GeneralUsageCategory.Name, DataType = p.DataType.Identifier, EntityTypeName = p.DataEntityType?.Name, LocalFacets = p.PropertyFacetValues ?.Select(v => PropertyFacet.Create(v)) ?.ToDictionary(v => v.Name, v => v), ForeignKeyName = p.ForeignKeyProperty?.Name, InversePropertyName = p.InverseProperty?.Name, Title = p.Title, IsNullable = p.IsNullable, IsExpression = p.IsExpression, Behaviors = p.PropertyBehaviors?.Select(x => new PropertyBehaviorMetadata { BehaviorName = x.AdditionalBehavior.Name, Parameters = x.Parameters })?.ToList() }).ToDictionary(p => p.Name, p => p) }).ToDictionary(x => x.Name, x => x as IEntityTypeMetadataModel); }
public async Task <ActionResult <MetadataValidationResponse> > GenerateCode() { if (!_permissionService.IsAllowed(new ActionRequestInfo(HttpContext, _implementationContainer, null, ActionTypeEnum.ManageMetadata))) { return(Unauthorized()); } var bundle = await MetadataBundle.FromDbWithoutNavigations(_dbContext , _implementationContainer.InstanceInfo.AppTypeId, _implementationContainer.InstanceInfo.AppInstanceId); bundle.FixupRelationships(); var metadataCache = new MetadataCache(bundle); var errorList = await GenerateCodeValidation(); var result = new MetadataValidationResponse(); if (errorList.Value?.Success != true) { return(errorList); } var r = await _assemblyGenerator.GenerateCode(metadataCache, _implementationContainer.InstanceInfo , _globalConfiguration.ImplementationsDirectory, _implementationContainer.InstanceInfo.InstanceName); if (!r.Succeeded) { result.Errors.AddRange(r.Diagnostics.Select(x => x.Message)); result.Success = false; return(result); } var copyFileName = _implementationContainer.InstanceInfo.InstanceSettings?.CopyAutoGeneratedEntitiesTo; if (!string.IsNullOrWhiteSpace(copyFileName)) { try { System.IO.File.Copy(r.SourceCodeFileName, copyFileName, true); } catch (Exception ex) { result.Errors.Add("Could not copy source code to: " + copyFileName + "Reson: " + ex.GetFullMessage()); } } result.Success = true; return(result); }
public MetadataCache(MetadataBundle bundle) { _dataTypesByIndetifier = bundle.DataTypes.ToDictionary(x => x.Identifier); LoadEntityGeneralUsageCategories(bundle); LoadPropertyGeneralUsageCategories(bundle); if (!_facetsDefined) { _facetsDefined = true; EntityTypeMetadata.DefineFacets(bundle.EntityTypeFacetDefinitions); PropertyMetadata.DefineFacets(bundle.PropertyFacetDefinitions); foreach (var defaultValue in bundle.PropertyFacetDefaultValues) { (PropertyMetadata._facets[defaultValue.FacetDefinitionId] as IMetadataFacet <PropertyGeneralUsageCategoryStruct>) .AddDefaultValue(GetPropertyGeneralUsageCategory(defaultValue.GeneralUsageCategoryId), defaultValue.DefaultValue); } foreach (var defaultValue in bundle.EntityTypeFacetDefaultValues) { (EntityTypeMetadata._facets[defaultValue.GeneralUsageCategoryId] as IMetadataFacet <EntityGeneralUsageCategoryStruct>) .AddDefaultValue(GetEntityGeneralUsageCategory(defaultValue.GeneralUsageCategoryId), defaultValue.DefaultValue); } } var map = new Dictionary <int, PropertyMetadata>(); foreach (var dbEntityMetadata in bundle.EntityTypes) { var entityTypeMetadata = new EntityTypeMetadata(dbEntityMetadata, null); foreach (var dbPropertyMetadata in dbEntityMetadata.Properties ?? Enumerable.Empty <Property>()) { var propertyMetadata = new PropertyMetadata(this, dbPropertyMetadata.Name, entityTypeMetadata, new PropertyGeneralUsageCategoryStruct { PropertyGeneralUsageCategoryId = dbPropertyMetadata.GeneralUsageCategoryId, Name = dbPropertyMetadata.GeneralUsageCategory.Name }, dbPropertyMetadata.DataType, dbPropertyMetadata.IsNullable, dbPropertyMetadata.IsExpression, dbPropertyMetadata.Title, dbPropertyMetadata.ExpressionDefinition?.Identifier, dbPropertyMetadata.PropertyBehaviors) { EntityTypeName = dbPropertyMetadata.DataEntityType?.Name }; map.Add(dbPropertyMetadata.Id, propertyMetadata); if (dbPropertyMetadata.PropertyFacetValues != null) { foreach (var facetValue in dbPropertyMetadata.PropertyFacetValues) { dynamic facet = PropertyMetadata._facets[facetValue.FacetDefinitionId]; propertyMetadata.SetValue(facet, facetValue.Value); } } } if (dbEntityMetadata.FacetValues != null) { foreach (var facetValue in dbEntityMetadata.FacetValues) { dynamic facet = EntityTypeMetadata._facets[facetValue.FacetDefinitionId]; entityTypeMetadata.SetValue(facet, facetValue.Value); } } _entityTypesByName.Add(dbEntityMetadata.Name, entityTypeMetadata); _entityTypesById.Add(dbEntityMetadata.Id, entityTypeMetadata); } foreach (var property in bundle.EntityTypes.Where(x => x.Properties != null).SelectMany(x => x.Properties)) { if (property.ForeignKeyPropertyId.HasValue) { map[property.Id].ForeignKey = map[property.ForeignKeyPropertyId.Value]; } if (property.InversePropertyId.HasValue) { map[property.Id].InverseProperty = map[property.InversePropertyId.Value]; } } foreach (var entityType in bundle.EntityTypes.Where(x => x.BaseEntityTypeId.HasValue)) { _entityTypesByName[entityType.Name].BaseEntityType = _entityTypesByName[entityType.BaseEntityType.Name]; } _expressions = new Dictionary <string, ExpressionInfo>(); foreach (var expressionDefiniction in bundle.ExpressionDefinitions) { _expressions.Add(expressionDefiniction.Identifier, new ExpressionInfo { MainInputEntityTypeName = expressionDefiniction.MainInputEntityType.Name }); } foreach (var body in bundle.ExpressionBodies) { if (!_expressions.TryGetValue(body.Definition.Identifier, out var info)) { continue; } info.Format = body.FormatId; info.Body = body.Body; } }
public static async Task <ImplementationContainer> Create(IServiceScope scope, MetadataDbContext dbContext, int appInstanceId) { var instance = await dbContext.AppInstances.FirstOrDefaultAsync(x => x.Id == appInstanceId); if (instance == null) { return(null); } if (!instance.IsEnabled) { return(null); } var appType = await dbContext.AppTypes.FirstOrDefaultAsync(x => x.Id == instance.AppTypeId); var bundle = await MetadataBundle.FromDbWithoutNavigations(dbContext, instance.AppTypeId, instance.Id); bundle.FixupRelationships(); var metadataCache = new MetadataCache(bundle); var metadataModel = new MetadataModel(bundle); var globalConfig = scope.ServiceProvider.GetRequiredService <IOptions <GlobalConfiguration> >().Value; var config = scope.ServiceProvider.GetRequiredService <IConfiguration>(); var dataConnectionStringTemplate = config.GetConnectionString(instance.DataConnectionStringTemplateName); if (string.IsNullOrWhiteSpace(dataConnectionStringTemplate)) { var logger = scope.ServiceProvider.GetRequiredService <ILogger <ImplementationContainer> >(); logger.LogError($"No connection stirng named \"{instance.DataConnectionStringTemplateName}\" which is required for app instance {instance.Name}"); } var lobConnectionStringTemplate = config.GetConnectionString(instance.LobConnectionStringTemplateName); if (string.IsNullOrWhiteSpace(lobConnectionStringTemplate)) { var logger = scope.ServiceProvider.GetRequiredService <ILogger <ImplementationContainer> >(); logger.LogError($"No connection stirng named \"{instance.LobConnectionStringTemplateName}\" which is required for app instance {instance.Name}"); } InstanceSettings instanceSettings = null; globalConfig?.InstanceSettings?.TryGetValue(instance.Name, out instanceSettings); var instanceInfo = new InstanceInfo { AppInstanceId = appInstanceId, AppTypeId = appType.Id, InstanceName = instance.Name, Provider = instance.DatabaseProviderId, DataConnectionString = GetConnectionString(dataConnectionStringTemplate, instance.MainDatabaseName), LobConnectionString = GetConnectionString(lobConnectionStringTemplate, instance.LobDatabaseName), MigrateDatabase = instance.MigrateDatabase, GeneratedCodeNamespace = instance.GeneratedCodeNamespace, DbContextName = instance.DbContextName, InstanceSettings = instanceSettings, LoadBusinessFromAssemblyName = instanceSettings?.LoadBusinessFromAssemblyName, SortOrder = instance.SortOrder, }; var bridge = new BusinessAssemblyBridge( instanceInfo, globalConfig, scope.ServiceProvider.GetRequiredService <ILogger <BusinessAssemblyBridge> >()); var reflector = new BusinessReflector(metadataCache); var implementationsContainer = new ImplementationContainer { Metadata = metadataCache, MetadataModel = metadataModel, BusinessAssemblyBridge = bridge, Reflector = reflector, InstanceInfo = instanceInfo }; switch (instanceInfo.Provider) { case DatabaseProviderEnum.MySql: var mySqlDbContextOptionsBuilder = new DbContextOptionsBuilder <LobToolsDbContext_MySql>(); implementationsContainer._lobToolsDbContextOptions = mySqlDbContextOptionsBuilder .UseMySql(instanceInfo.LobConnectionString, ServerVersion.AutoDetect(instanceInfo.LobConnectionString)).Options; break; case DatabaseProviderEnum.SqlServer: var lobToolsDbContextOptionsBuilder = new DbContextOptionsBuilder <LobToolsDbContext>(); implementationsContainer._lobToolsDbContextOptions = lobToolsDbContextOptionsBuilder.UseSqlServer(instanceInfo.LobConnectionString).Options; break; case DatabaseProviderEnum.PostgreSql: var postgreSqlDbContextOptionsBuilder = new DbContextOptionsBuilder <LobToolsDbContext_PostgreSql>(); implementationsContainer._lobToolsDbContextOptions = postgreSqlDbContextOptionsBuilder.UseNpgsql(instanceInfo.LobConnectionString).Options; break; default: throw new NotImplementedException($"The provider {instanceInfo.Provider} is not implemented"); } if (bridge.BusinessDbContextFactory == null) { scope.ServiceProvider.GetRequiredService <ILogger <ImplementationContainer> >().LogError($"Business assembly not loaded"); } else { var dbContextType = bridge.BusinessDbContextFactory.GetType().Assembly.GetTypes().Single(x => x.IsPublic && x.IsSubclassOf(typeof(DbContext))); reflector.RegisterAssembly(dbContextType.Assembly); var dbContextOptionsBuilder = Activator.CreateInstance(typeof(DbContextOptionsBuilder <>).MakeGenericType(dbContextType)) as DbContextOptionsBuilder; switch (instanceInfo.Provider) { case DatabaseProviderEnum.MySql: implementationsContainer._dbContextOptions = dbContextOptionsBuilder .UseMySql(instanceInfo.DataConnectionString, ServerVersion.AutoDetect(instanceInfo.DataConnectionString)).Options; break; case DatabaseProviderEnum.SqlServer: implementationsContainer._dbContextOptions = dbContextOptionsBuilder.UseSqlServer(instanceInfo.DataConnectionString).Options; break; case DatabaseProviderEnum.PostgreSql: implementationsContainer._dbContextOptions = dbContextOptionsBuilder.UseNpgsql(instanceInfo.DataConnectionString).Options; break; default: throw new NotImplementedException($"The provider {instanceInfo.Provider} is not implemented"); } } return(implementationsContainer); }
public static async Task <ImplementationContainer> Create(IServiceScope scope, MetadataDbContext dbContext, int appInstanceId) { var instance = await dbContext.AppInstances.FirstOrDefaultAsync(x => x.Id == appInstanceId); if (instance == null) { return(null); } if (!instance.IsEnabled) { return(null); } var appType = await dbContext.AppTypes.FirstOrDefaultAsync(x => x.Id == instance.AppTypeId); var bundle = await MetadataBundle.FromDbWithoutNavigations(dbContext, instance.AppTypeId, instance.Id); bundle.FixupRelationships(); var metadataCache = new MetadataCache(bundle); var metadataModel = new MetadataModel(bundle); var instanceInfo = new InstanceInfo { AppInstanceId = appInstanceId, AppTypeId = appType.Id, InstanceName = instance.Name, Provider = instance.DatabaseProviderId, ConnectionString = instance.DataConnectionString, MigrateDatabase = instance.MigrateDatabase }; var bridge = new BusinessAssemblyBridge( instanceInfo, scope.ServiceProvider.GetRequiredService <IOptions <GlobalConfiguration> >().Value, scope.ServiceProvider.GetRequiredService <ILogger <BusinessAssemblyBridge> >()); var reflector = new BusinessReflector(metadataCache); var implementationsContainer = new ImplementationContainer { Metadata = metadataCache, MetadataModel = metadataModel, BusinessAssemblyBridge = bridge, Reflector = reflector, InstanceInfo = instanceInfo }; if (bridge.BusinessDbContextFactory == null) { scope.ServiceProvider.GetRequiredService <ILogger <ImplementationContainer> >().LogError($"Business assembly not loaded"); } else { var dbContextType = bridge.BusinessDbContextFactory.GetType().Assembly.GetTypes().Single(x => x.IsSubclassOf(typeof(DbContext))); reflector.RegisterAssembly(dbContextType.Assembly); var dbContextOptionsBuilder = Activator.CreateInstance(typeof(DbContextOptionsBuilder <>).MakeGenericType(dbContextType)) as DbContextOptionsBuilder; switch (instanceInfo.Provider) { case DatabaseProviderEnum.MySql: implementationsContainer._dbContextOptions = dbContextOptionsBuilder.UseMySql(instanceInfo.ConnectionString).Options; break; case DatabaseProviderEnum.SqlServer: implementationsContainer._dbContextOptions = dbContextOptionsBuilder.UseSqlServer(instanceInfo.ConnectionString).Options; break; default: throw new NotImplementedException($"The provider {instanceInfo.Provider} is not implemented"); } } return(implementationsContainer); }