public async Task <SyntaxTree> AddNewContext(NewDbContextTemplateModel dbContextTemplateModel) { if (dbContextTemplateModel == null) { throw new ArgumentNullException(nameof(dbContextTemplateModel)); } var templateName = "NewLocalDbContext.cshtml"; var templatePath = _filesLocator.GetFilePath(templateName, TemplateFolders); Contract.Assert(File.Exists(templatePath)); var templateContent = File.ReadAllText(templatePath); var templateResult = await _templatingService.RunTemplateAsync(templateContent, dbContextTemplateModel); if (templateResult.ProcessingException != null) { throw new InvalidOperationException(string.Format( MessageStrings.TemplateProcessingError, templatePath, templateResult.ProcessingException.Message)); } var newContextContent = templateResult.GeneratedText; var sourceText = SourceText.From(newContextContent); return(CSharpSyntaxTree.ParseText(sourceText)); }
public async Task <ContextProcessingResult> GetModelMetadata(string dbContextFullTypeName, ModelType modelTypeSymbol) { 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(); Type modelReflectionType = null; if (dbContextSymbols.Count == 0) { await ValidateEFSqlServerDependency(); // Create a new Context _logger.LogMessage("Generating a new DbContext class " + dbContextFullTypeName); var dbContextTemplateModel = new NewDbContextTemplateModel(dbContextFullTypeName, modelTypeSymbol); 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("Attempting to compile the application in memory with the added DbContext"); CompileAndGetDbContextAndModelTypes(dbContextFullTypeName, modelTypeSymbol.FullName, c => { c = c.AddSyntaxTrees(dbContextSyntaxTree); if (startUpEditResult.Edited) { c = c.ReplaceSyntaxTree(startUpEditResult.OldTree, startUpEditResult.NewTree); } return(c); }, out dbContextType, out modelReflectionType); // Add file information dbContextSyntaxTree = dbContextSyntaxTree.WithFilePath(GetPathForNewContext(dbContextTemplateModel.DbContextTypeName)); } else { var addResult = _dbContextEditorServices.AddModelToContext(dbContextSymbols.First(), modelTypeSymbol); if (addResult.Edited) { state = ContextProcessingStatus.ContextEdited; dbContextSyntaxTree = addResult.NewTree; _logger.LogMessage("Attempting to compile the application in memory with the modified DbContext"); CompileAndGetDbContextAndModelTypes(dbContextFullTypeName, modelTypeSymbol.FullName, c => { var oldTree = c.SyntaxTrees.FirstOrDefault(t => t.FilePath == addResult.OldTree.FilePath); Debug.Assert(oldTree != null); return(c.ReplaceSyntaxTree(oldTree, addResult.NewTree)); }, out dbContextType, out modelReflectionType); } else { _logger.LogMessage("Attempting to compile the application in memory"); CompileAndGetDbContextAndModelTypes(dbContextFullTypeName, modelTypeSymbol.FullName, c => { return(c); }, out dbContextType, out modelReflectionType); if (dbContextType == null) { throw new InvalidOperationException(string.Format(MessageStrings.DbContextTypeNotFound, dbContextFullTypeName)); } } } if (modelReflectionType == null) { throw new InvalidOperationException(string.Format(MessageStrings.ModelTypeNotFound, modelTypeSymbol.Name)); } _logger.LogMessage("Attempting to figure out the EntityFramework metadata for the model and DbContext: " + modelTypeSymbol.Name); var metadata = GetModelMetadata(dbContextType, modelReflectionType, startupType); // 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("Added DbContext : " + dbContextSyntaxTree.FilePath.Substring(_applicationInfo.ApplicationBasePath.Length)); if (state != ContextProcessingStatus.ContextAddedButRequiresConfig) { PersistSyntaxTree(startUpEditResult.NewTree); } else { _logger.LogMessage("However there may be additional steps required for the generted code to work properly, refer to documentation <forward_link>."); } } } return(new ContextProcessingResult() { ContextProcessingStatus = state, ModelMetadata = metadata }); }