public async Task <ContextProcessingResult> GetModelMetadata(ModelType modelType) { if (modelType == null) { throw new ArgumentNullException(nameof(modelType)); } var projectCompilation = await _workspace.CurrentSolution.Projects .First(project => project.AssemblyName == _projectContext.AssemblyName) .GetCompilationAsync(); var reflectedTypesProvider = new ReflectedTypesProvider( projectCompilation, (c) => c, _projectContext, _loader, _logger); var modelReflectionType = reflectedTypesProvider.GetReflectedType( modelType: modelType.FullName, lookInDependencies: true); if (modelReflectionType == null) { throw new InvalidOperationException(string.Format(MessageStrings.ModelTypeNotFound, modelType.Name)); } var modelMetadata = new CodeModelMetadata(modelReflectionType); return(new ContextProcessingResult() { ContextProcessingStatus = ContextProcessingStatus.ContextAvailable, ModelMetadata = modelMetadata }); }
private async Task AddModelTypeToExistingDbContextIfNeeded(ModelType dbContextSymbol) { var addResult = _dbContextEditorServices.AddModelToContext(dbContextSymbol, _modelTypeSymbol); var projectCompilation = await _workspace.CurrentSolution.Projects .First(project => project.AssemblyName == _projectContext.AssemblyName) .GetCompilationAsync(); if (addResult.Edited) { ContextProcessingStatus = ContextProcessingStatus.ContextEdited; _dbContextSyntaxTree = addResult.NewTree; _logger.LogMessage(MessageStrings.CompilingWithModifiedDbContext); _reflectedTypesProvider = GetReflectedTypesProvider( projectCompilation, c => { c = c.AddSyntaxTrees(_assemblyAttributeGenerator.GenerateAttributeSyntaxTree()); var oldTree = c.SyntaxTrees.FirstOrDefault(t => t.FilePath == addResult.OldTree.FilePath); if (oldTree == null) { throw new InvalidOperationException(string.Format( MessageStrings.ModelTypeCouldNotBeAdded, _modelTypeSymbol.FullName, _dbContextFullTypeName)); } return(c.ReplaceSyntaxTree(oldTree, addResult.NewTree)); }); var compilationErrors = _reflectedTypesProvider.GetCompilationErrors(); _dbContextError = string.Format( MessageStrings.DbContextCreationError, (compilationErrors == null ? string.Empty : string.Join(Environment.NewLine, compilationErrors))); } else { _logger.LogMessage(MessageStrings.CompilingInMemory); _reflectedTypesProvider = GetReflectedTypesProvider( projectCompilation, c => { c = c.AddSyntaxTrees(_assemblyAttributeGenerator.GenerateAttributeSyntaxTree()); return(c); }); _dbContextError = string.Format(MessageStrings.DbContextTypeNotFound, _dbContextFullTypeName); } }
private async Task EnsureDbContextInLibraryIsValid(ModelType dbContextSymbol) { var projectCompilation = await _workspace.CurrentSolution.Projects .First(project => project.AssemblyName == _projectContext.AssemblyName) .GetCompilationAsync(); _reflectedTypesProvider = GetReflectedTypesProvider( projectCompilation, c => { c = c.AddSyntaxTrees(_assemblyAttributeGenerator.GenerateAttributeSyntaxTree()); return(c); }); var dbContextType = _reflectedTypesProvider.GetReflectedType(_dbContextFullTypeName, lookInDependencies: true); if (_reflectedTypesProvider.GetCompilationErrors() != null && _reflectedTypesProvider.GetCompilationErrors().Any()) { throw new InvalidOperationException(string.Format( MessageStrings.FailedToCompileInMemory, string.Join(Environment.NewLine, _reflectedTypesProvider.GetCompilationErrors()) )); } var props = dbContextType.GetProperties() .Where(p => p.PropertyType.IsGenericType && p.PropertyType.GenericTypeArguments.Any() && p.PropertyType.Name.Equals("DbSet`1") && p.PropertyType.Namespace.Equals("Microsoft.EntityFrameworkCore")); if (!props.Any(p => p.PropertyType.GenericTypeArguments[0].FullName.Equals(_modelTypeSymbol.FullName))) { throw new InvalidOperationException(string.Format( MessageStrings.ModelTypeCouldNotBeAdded, _modelTypeSymbol.FullName, _dbContextFullTypeName)); } }
private async Task GenerateNewDbContextAndRegister(ModelType startupType, ModelType programType) { AssemblyAttributeGenerator assemblyAttributeGenerator = GetAssemblyAttributeGenerator(); _startupEditResult = new EditSyntaxTreeResult() { Edited = false }; ValidateEFSqlServerDependency(); // Create a new Context _logger.LogMessage(string.Format(MessageStrings.GeneratingDbContext, _dbContextFullTypeName)); var dbContextTemplateModel = new NewDbContextTemplateModel(_dbContextFullTypeName, _modelTypeSymbol, programType); _dbContextSyntaxTree = await _dbContextEditorServices.AddNewContext(dbContextTemplateModel); ContextProcessingStatus = ContextProcessingStatus.ContextAdded; if (startupType != null) { _startupEditResult = _dbContextEditorServices.EditStartupForNewContext(startupType, dbContextTemplateModel.DbContextTypeName, dbContextTemplateModel.DbContextNamespace, dataBaseName: dbContextTemplateModel.DbContextTypeName + "-" + Guid.NewGuid().ToString()); } if (!_startupEditResult.Edited) { ContextProcessingStatus = ContextProcessingStatus.ContextAddedButRequiresConfig; // The created context would anyway fail to fetch metadata with a crypic message // It's better to throw with a meaningful message throw new InvalidOperationException(string.Format("{0} {1}", MessageStrings.FailedToEditStartup, MessageStrings.EnsureStartupClassExists)); } _logger.LogMessage(MessageStrings.CompilingWithAddedDbContext); var projectCompilation = await _workspace.CurrentSolution.Projects .First(project => project.AssemblyName == _projectContext.AssemblyName) .GetCompilationAsync(); _reflectedTypesProvider = GetReflectedTypesProvider( projectCompilation, c => { c = c.AddSyntaxTrees(assemblyAttributeGenerator.GenerateAttributeSyntaxTree()); c = c.AddSyntaxTrees(_dbContextSyntaxTree); if (_startupEditResult.Edited) { c = c.ReplaceSyntaxTree(_startupEditResult.OldTree, _startupEditResult.NewTree); } return(c); }); var compilationErrors = _reflectedTypesProvider.GetCompilationErrors(); _dbContextError = string.Format( MessageStrings.DbContextCreationError, (compilationErrors == null ? string.Empty : string.Join(Environment.NewLine, compilationErrors))); _dbContextSyntaxTree = _dbContextSyntaxTree.WithFilePath(GetPathForNewContext(dbContextTemplateModel.DbContextTypeName, _areaName)); }
public async Task <ContextProcessingResult> GetModelMetadata(string dbContextFullTypeName, ModelType modelTypeSymbol, string areaName) { Type dbContextType; SyntaxTree dbContextSyntaxTree = null; EditSyntaxTreeResult startUpEditResult = new EditSyntaxTreeResult() { Edited = false }; ContextProcessingStatus state = ContextProcessingStatus.ContextAvailable; var dbContextSymbols = _modelTypesLocator.GetType(dbContextFullTypeName).ToList(); var startupType = _modelTypesLocator.GetType("Startup").FirstOrDefault(); var programType = _modelTypesLocator.GetType("Program").FirstOrDefault(); Type modelReflectionType = null; ReflectedTypesProvider reflectedTypesProvider = null; string dbContextError = string.Empty; AssemblyAttributeGenerator assemblyAttributeGenerator = GetAssemblyAttributeGenerator(); if (dbContextSymbols.Count == 0) { ValidateEFSqlServerDependency(); // Create a new Context _logger.LogMessage(string.Format(MessageStrings.GeneratingDbContext, dbContextFullTypeName)); var dbContextTemplateModel = new NewDbContextTemplateModel(dbContextFullTypeName, modelTypeSymbol, programType); dbContextSyntaxTree = await _dbContextEditorServices.AddNewContext(dbContextTemplateModel); state = ContextProcessingStatus.ContextAdded; // Edit startup class to register the context using DI if (startupType != null) { startUpEditResult = _dbContextEditorServices.EditStartupForNewContext(startupType, dbContextTemplateModel.DbContextTypeName, dbContextTemplateModel.DbContextNamespace, dataBaseName: dbContextTemplateModel.DbContextTypeName + "-" + Guid.NewGuid().ToString()); } if (!startUpEditResult.Edited) { state = ContextProcessingStatus.ContextAddedButRequiresConfig; // The created context would anyway fail to fetch metadata with a crypic message // It's better to throw with a meaningful message throw new InvalidOperationException(string.Format("{0} {1}", MessageStrings.FailedToEditStartup, MessageStrings.EnsureStartupClassExists)); } _logger.LogMessage(MessageStrings.CompilingWithAddedDbContext); var projectCompilation = await _workspace.CurrentSolution.Projects .First(project => project.AssemblyName == _projectContext.AssemblyName) .GetCompilationAsync(); reflectedTypesProvider = new ReflectedTypesProvider( projectCompilation, c => { c = c.AddSyntaxTrees(assemblyAttributeGenerator.GenerateAttributeSyntaxTree()); c = c.AddSyntaxTrees(dbContextSyntaxTree); if (startUpEditResult.Edited) { c = c.ReplaceSyntaxTree(startUpEditResult.OldTree, startUpEditResult.NewTree); } return(c); }, _projectContext, _loader, _logger); var compilationErrors = reflectedTypesProvider.GetCompilationErrors(); dbContextError = string.Format( MessageStrings.DbContextCreationError, (compilationErrors == null ? string.Empty : string.Join(Environment.NewLine, compilationErrors))); // Add file information dbContextSyntaxTree = dbContextSyntaxTree.WithFilePath(GetPathForNewContext(dbContextTemplateModel.DbContextTypeName, areaName)); } else { var addResult = _dbContextEditorServices.AddModelToContext(dbContextSymbols.First(), modelTypeSymbol); var projectCompilation = await _workspace.CurrentSolution.Projects .First(project => project.AssemblyName == _projectContext.AssemblyName) .GetCompilationAsync(); if (addResult.Edited) { state = ContextProcessingStatus.ContextEdited; dbContextSyntaxTree = addResult.NewTree; _logger.LogMessage(MessageStrings.CompilingWithModifiedDbContext); reflectedTypesProvider = new ReflectedTypesProvider( projectCompilation, c => { c = c.AddSyntaxTrees(assemblyAttributeGenerator.GenerateAttributeSyntaxTree()); var oldTree = c.SyntaxTrees.FirstOrDefault(t => t.FilePath == addResult.OldTree.FilePath); if (oldTree == null) { throw new InvalidOperationException(string.Format( MessageStrings.ModelTypeCouldNotBeAdded, modelTypeSymbol.FullName, dbContextFullTypeName)); } return(c.ReplaceSyntaxTree(oldTree, addResult.NewTree)); }, _projectContext, _loader, _logger); var compilationErrors = reflectedTypesProvider.GetCompilationErrors(); dbContextError = string.Format( MessageStrings.DbContextCreationError, (compilationErrors == null ? string.Empty : string.Join(Environment.NewLine, compilationErrors))); } else { _logger.LogMessage(MessageStrings.CompilingInMemory); reflectedTypesProvider = new ReflectedTypesProvider( projectCompilation, c => { c = c.AddSyntaxTrees(assemblyAttributeGenerator.GenerateAttributeSyntaxTree()); return(c); }, _projectContext, _loader, _logger); dbContextError = string.Format(MessageStrings.DbContextTypeNotFound, dbContextFullTypeName); } } dbContextType = reflectedTypesProvider.GetReflectedType( modelType: dbContextFullTypeName, lookInDependencies: true); if (dbContextType == null) { throw new InvalidOperationException(dbContextError); } modelReflectionType = reflectedTypesProvider.GetReflectedType( modelType: modelTypeSymbol.FullName, lookInDependencies: true); if (modelReflectionType == null) { throw new InvalidOperationException(string.Format(MessageStrings.ModelTypeNotFound, modelTypeSymbol.Name)); } var reflectedStartupType = reflectedTypesProvider.GetReflectedType( modelType: startupType.FullName, lookInDependencies: true); if (reflectedStartupType == null) { throw new InvalidOperationException(string.Format(MessageStrings.ModelTypeNotFound, reflectedStartupType.Name)); } _logger.LogMessage(string.Format(MessageStrings.GettingEFMetadata, modelTypeSymbol.Name)); var metadata = GetModelMetadata(dbContextType, modelReflectionType, reflectedStartupType); // Write the DbContext/Startup if getting the model metadata is successful if (dbContextSyntaxTree != null) { PersistSyntaxTree(dbContextSyntaxTree); if (state == ContextProcessingStatus.ContextAdded || state == ContextProcessingStatus.ContextAddedButRequiresConfig) { _logger.LogMessage(string.Format(MessageStrings.AddedDbContext, dbContextSyntaxTree.FilePath.Substring(_applicationInfo.ApplicationBasePath.Length))); if (state != ContextProcessingStatus.ContextAddedButRequiresConfig) { PersistSyntaxTree(startUpEditResult.NewTree); } else { _logger.LogMessage(MessageStrings.AdditionalSteps); } } } return(new ContextProcessingResult() { ContextProcessingStatus = state, ModelMetadata = metadata }); }