コード例 #1
0
        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
            });
        }
コード例 #2
0
        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);
            }
        }
コード例 #3
0
        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));
            }
        }
コード例 #4
0
        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));
        }
コード例 #5
0
        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
            });
        }