Ejemplo n.º 1
0
        private async Task InsertRequestPipelineMiddlewareRegistrations()
        {
            try
            {
                var pipelineAdditions = await _taskManager.ManagedRun(_taskId, (token) => _lifecycleManager.GetMiddlewarePipelineAdditions(token));

                _configureMethodStatements = _configureMethodStatements.Concat(pipelineAdditions);
            }
            catch (OperationCanceledException e)
            {
                LogHelper.LogError(e, string.Format(
                                       Constants.CaneledServiceCallLogTemplate,
                                       Rules.Config.Constants.WebFormsErrorTag,
                                       GetType().Name,
                                       typeof(LifecycleManagerService).Name,
                                       GetMiddlewarePipelineAdditionsLogCall));

                var failureComment = string.Format(Constants.OperationFailedCommentTemplate, ConfigureRequestPipelineOperation);

                if (!_configureMethodStatements.Any())
                {
                    // If we don't have any extra statements for configure() add a blank
                    // one to attach our comment to
                    _configureMethodStatements = _configureMethodStatements.Append(CodeSyntaxHelper.GetBlankLine().AddComment(failureComment, isLeading: false));
                }
                else
                {
                    _configureMethodStatements = _configureMethodStatements.AddComment(failureComment, isLeading: false);
                }
            }
        }
Ejemplo n.º 2
0
        public override Task <IEnumerable <FileInformation> > MigrateClassAsync()
        {
            LogStart();

            _metricsContext.CollectActionMetrics(WebFormsActionType.ClassConversion, ActionName);
            // NOTE: We could just read the file from the disk and retrieve the bytes like
            // that but instead I opted to "rebuild" the type in case we wanted to add comments
            // or something else to these undefined code files, most likely though we may still
            // want to scan parts of these files and remove/alter/take note of certain lines/info

            var newRelativePath = FilePathHelper.RemoveDuplicateDirectories(FilePathHelper.AlterFileName(_relativePath, newFileName: _originalClassSymbol.Name));

            // NOTE: Removed temporarily until usings can be better determined, at the moment, too
            // many are being removed
            //var sourceClassComponents = GetSourceClassComponents();

            var namespaceNames = _sourceFileSemanticModel.GetOriginalUsingNamespaces().Append(Constants.BlazorComponentsNamespace);

            namespaceNames = CodeSyntaxHelper.RemoveFrameworkUsings(namespaceNames);
            var usingStatements = CodeSyntaxHelper.BuildUsingStatements(namespaceNames);
            var namespaceNode   = CodeSyntaxHelper.BuildNamespace(_originalClassSymbol.ContainingNamespace?.ToDisplayString(), _originalDeclarationSyntax);
            var fileText        = CodeSyntaxHelper.GetFileSyntaxAsString(namespaceNode, usingStatements);

            DoCleanUp();
            LogEnd();

            var result = new[] { new FileInformation(newRelativePath, Encoding.UTF8.GetBytes(fileText)) };

            return(Task.FromResult((IEnumerable <FileInformation>)result));
        }
Ejemplo n.º 3
0
        private async Task <IEnumerable <UsingDirectiveSyntax> > GetAllUsingStatements()
        {
            // NOTE: Removed temporarily until usings can be better determined, at the moment, too
            // many are being removed
            //var typeRequiredNamespaceNames = _sourceFileSemanticModel
            //    .GetNamespacesReferencedByType(_originalDeclarationSyntax)
            //    .Select(namespaceSymbol => namespaceSymbol.ToDisplayString());

            var typeRequiredNamespaceNames = _sourceFileSemanticModel.GetOriginalUsingNamespaces();

            typeRequiredNamespaceNames = CodeSyntaxHelper.RemoveFrameworkUsings(typeRequiredNamespaceNames);

            // Merging required using statements for middleware and source type contents
            try
            {
                var middlewareNamespaceNames = await _taskManager.ManagedRun(_taskId, (token) => _lifecycleManager.GetMiddlewareNamespaces(token));

                return(CodeSyntaxHelper.BuildUsingStatements(typeRequiredNamespaceNames.Union(middlewareNamespaceNames).Union(StartupSyntaxHelper.RequiredNamespaces)));
            }
            catch (OperationCanceledException e)
            {
                LogHelper.LogError(e, string.Format(
                                       Constants.CaneledServiceCallLogTemplate,
                                       Rules.Config.Constants.WebFormsErrorTag,
                                       GetType().Name,
                                       typeof(LifecycleManagerService).Name,
                                       GetMiddlewareNamespacesLogCall));

                return(CodeSyntaxHelper.BuildUsingStatements(typeRequiredNamespaceNames)
                       .AddComment(string.Format(Constants.OperationFailedCommentTemplate, AddMiddlewareUsingsOperation)));
            }
        }
Ejemplo n.º 4
0
        public override Task <IEnumerable <FileInformation> > MigrateClassAsync()
        {
            LogStart();
            _metricsContext.CollectActionMetrics(WebFormsActionType.ClassConversion, ActionName);
            // NOTE: Removed temporarily until usings can be better determined, at the moment, too
            // many are being removed
            //var requiredNamespaces = _sourceFileSemanticModel.GetNamespacesReferencedByType(_originalDeclarationSyntax);
            //var namespaceNames = requiredNamespaces.Select(namespaceSymbol => namespaceSymbol.ToDisplayString()).Append(Constants.BlazorComponentsNamespace);

            var requiredNamespaces = _sourceFileSemanticModel.GetOriginalUsingNamespaces().Append(Constants.BlazorComponentsNamespace);

            requiredNamespaces = CodeSyntaxHelper.RemoveFrameworkUsings(requiredNamespaces);

            var usingStatements = CodeSyntaxHelper.BuildUsingStatements(requiredNamespaces);

            var modifiedClass = ((ClassDeclarationSyntax)_originalDeclarationSyntax)
                                // Remove outdated base type references
                                // TODO: Scan and remove specific base types in the future
                                .ClearBaseTypes()
                                // ComponentBase base class is added because user controls become
                                // normal razor components
                                .AddBaseType(Constants.ComponentBaseClass);

            var namespaceNode = CodeSyntaxHelper.BuildNamespace(_originalClassSymbol.ContainingNamespace?.ToDisplayString(), modifiedClass);

            DoCleanUp();
            LogEnd();

            var newRelativePath = GetNewRelativePath();
            var fileContent     = CodeSyntaxHelper.GetFileSyntaxAsString(namespaceNode, usingStatements);
            var result          = new[] { new FileInformation(newRelativePath, Encoding.UTF8.GetBytes(fileContent)) };

            return(Task.FromResult((IEnumerable <FileInformation>)result));
        }
Ejemplo n.º 5
0
        public void GetFileSyntaxAsString_Properly_Namespace_And_Usings_For_Full_File_Text()
        {
            var usingsCollection     = CodeSyntaxHelper.BuildUsingStatements(new[] { TestReferencedNamespace1, TestReferencedNamespace2 });
            var classDeclaration     = SyntaxFactory.ClassDeclaration(TestClassName);
            var namespaceDeclaration = CodeSyntaxHelper.BuildNamespace(TestNamespaceName, classDeclaration);

            Assert.AreEqual(ExpectedTestFileText, CodeSyntaxHelper.GetFileSyntaxAsString(namespaceDeclaration, usingsCollection));
        }
Ejemplo n.º 6
0
        public void GetStatementsAsBlock_Inserts_Statements_Into_Braced_Code_Block()
        {
            var actualCodeBlockText = CodeSyntaxHelper.GetStatementsAsBlock(new[] {
                SyntaxFactory.ParseStatement(TestStatement1), SyntaxFactory.ParseStatement(TestStatement2)
            }).NormalizeWhitespace().ToFullString();

            Assert.AreEqual(ExpectedBlockText, actualCodeBlockText);
        }
Ejemplo n.º 7
0
        public void BuildNamespace_Correctly_Builds_Namespace_With_Null_NamespaceName()
        {
            var    classDeclaration    = SyntaxFactory.ClassDeclaration(TestClassName);
            string nullNamespaceName   = null;
            var    actualNamespaceText = CodeSyntaxHelper.BuildNamespace(nullNamespaceName, classDeclaration).NormalizeWhitespace().ToFullString();

            Assert.AreEqual(ExpectedTestNullNamespaceText, actualNamespaceText);
        }
Ejemplo n.º 8
0
        private protected SourceClassComponents GetSourceClassComponents()
        {
            var requiredNamespaces = _sourceFileSemanticModel.GetNamespacesReferencedByType(_originalDeclarationSyntax);
            var usingStatements    = CodeSyntaxHelper.BuildUsingStatements(requiredNamespaces);
            var namespaceNode      = CodeSyntaxHelper.BuildNamespace(_originalClassSymbol.ContainingNamespace?.ToDisplayString(), _originalDeclarationSyntax);
            var fileText           = CodeSyntaxHelper.GetFileSyntaxAsString(namespaceNode, usingStatements);

            return(new SourceClassComponents(requiredNamespaces, usingStatements, namespaceNode, fileText));
        }
Ejemplo n.º 9
0
        public void BuildUsingStatements_Correctly_Builds_Many_Using_Statements()
        {
            var expectedCollection = new[] {
                ExpectedTestReferencedNamespaceUsing1,
                ExpectedTestReferencedNamespaceUsing2
            };

            var actualCollection = CodeSyntaxHelper
                                   .BuildUsingStatements(new[] { TestReferencedNamespace1, TestReferencedNamespace2 })
                                   .Select(statement => statement.NormalizeWhitespace().ToFullString());

            Assert.AreEqual(expectedCollection, actualCollection);
        }
Ejemplo n.º 10
0
        public override async Task <IEnumerable <FileInformation> > MigrateClassAsync()
        {
            LogStart();
            _metricsContext.CollectActionMetrics(WebFormsActionType.ClassConversion, ActionName);

            // Make this call once now so we don't have to keep doing it later
            var originalDescendantNodes = _originalDeclarationSyntax.DescendantNodes();

            // Currently not implementing service layer so add blank line with a comment instead
            var configureServicesLines = new[]
            {
                CodeSyntaxHelper.GetBlankLine().AddComment(string.Format(Constants.OperationUnattemptedCommentTemplate, MigrateServiceLayerOperation), isLeading: false)
            };

            // Iterate through methods and process them as needed
            ProcessMethods(originalDescendantNodes.OfType <MethodDeclarationSyntax>());

            // With middleware lambdas added we need to retrieve registrations
            // before we have all statements required to build startup class
            await InsertRequestPipelineMiddlewareRegistrations();

            var fileText = string.Empty;

            try
            {
                var startupClassDeclaration = StartupSyntaxHelper.ConstructStartupClass(
                    constructorAdditionalStatements: originalDescendantNodes.OfType <ConstructorDeclarationSyntax>().FirstOrDefault()?.Body?.Statements,
                    configureAdditionalStatements: _configureMethodStatements,
                    configureServicesAdditionalStatements: configureServicesLines,
                    additionalFieldDeclarations: originalDescendantNodes.OfType <FieldDeclarationSyntax>(),
                    additionalPropertyDeclarations: originalDescendantNodes.OfType <PropertyDeclarationSyntax>(),
                    additionalMethodDeclarations: _keepableMethods)
                                              .AddClassBlockComment(_endOfClassComments, false);

                var containingNamespace = CodeSyntaxHelper.BuildNamespace(_originalClassSymbol.ContainingNamespace?.ToDisplayString(), startupClassDeclaration);
                fileText = CodeSyntaxHelper.GetFileSyntaxAsString(containingNamespace, await GetAllUsingStatements());
            }
            catch (Exception e)
            {
                LogHelper.LogError(e, $"{Rules.Config.Constants.WebFormsErrorTag}Failed to construct new Startup file content from {OriginalClassName} class at {_fullPath}");
            }

            DoCleanUp();
            LogEnd();

            // Global.asax.cs turns into Startup.cs
            var newRelativePath = FilePathHelper.RemoveDuplicateDirectories(Path.Combine(Path.GetDirectoryName(_relativePath), Constants.StartupFileName));

            return(new[] { new FileInformation(newRelativePath, Encoding.UTF8.GetBytes(fileText)) });
        }
Ejemplo n.º 11
0
        private void ProcessMethods(IEnumerable <MethodDeclarationSyntax> orignalMethods)
        {
            foreach (var method in orignalMethods)
            {
                try
                {
                    var lifecycleEvent = LifecycleManagerService.CheckMethodApplicationLifecycleHook(method);

                    if (lifecycleEvent != null)
                    {
                        HandleLifecycleMethod(method, (WebFormsAppLifecycleEvent)lifecycleEvent);
                    }
                    else if (method.IsEventHandler(ApplicationStartMethodName))
                    {
                        var newStatements = method.Body.Statements
                                            // Make a note of where these lines came from
                                            .AddComment(string.Format(Constants.CodeOriginCommentTemplate, ApplicationStartMethodName))
                                            // Add blank line before new statements to give some separation from previous statements
                                            .Prepend(CodeSyntaxHelper.GetBlankLine());

                        _configureMethodStatements = _configureMethodStatements.Concat(newStatements);
                    }
                    else if (method.IsEventHandler(ApplicationEndMethodName) || method.IsEventHandler(SessionStartMethodName) || method.IsEventHandler(SessionEndMethodName))
                    {
                        CommentOutMethod(method);
                    }
                    else
                    {
                        _keepableMethods = _keepableMethods.Append(method);
                    }
                }
                catch (Exception e)
                {
                    LogHelper.LogError(e, $"{Rules.Config.Constants.WebFormsErrorTag}Failed to process {method.Identifier} method in {OriginalClassName} class at {_fullPath}");
                }
            }

            // We added all discovered middleware methods as lambdas so global has been
            // processed as a middleware source
            _lifecycleManager.NotifyMiddlewareSourceProcessed();
        }
Ejemplo n.º 12
0
        private void ProcessLifecycleEventMethod(MethodDeclarationSyntax methodDeclaration, WebFormsPageLifecycleEvent lifecycleEvent)
        {
            var statements = (IEnumerable <StatementSyntax>)methodDeclaration.Body.Statements;

            // Dont do anything if the method is empty, no reason to move over nothing
            if (statements.Any())
            {
                statements = statements.AddComment(string.Format(Constants.NewEventRepresentationCommentTemplate, lifecycleEvent.ToString()));

                var blazorLifecycleEvent = LifecycleManagerService.GetEquivalentComponentLifecycleEvent(lifecycleEvent);

                if (_newLifecycleLines.ContainsKey(blazorLifecycleEvent))
                {
                    // Add spacing between last added method
                    statements = statements.Prepend(CodeSyntaxHelper.GetBlankLine());
                    _newLifecycleLines[blazorLifecycleEvent] = _newLifecycleLines[blazorLifecycleEvent].Concat(statements);
                }
                else
                {
                    _newLifecycleLines.Add(blazorLifecycleEvent, statements);
                }
            }
        }
Ejemplo n.º 13
0
        public override Task <IEnumerable <FileInformation> > MigrateClassAsync()
        {
            LogStart();

            _metricsContext.CollectActionMetrics(WebFormsActionType.ClassConversion, ActionName);
            // NOTE: Removed temporarily until usings can be better determined, at the moment, too
            // many are being removed
            // var requiredNamespaceNames = _sourceFileSemanticModel
            //     .GetNamespacesReferencedByType(_originalDeclarationSyntax)
            //     .Select(namespaceSymbol => namespaceSymbol.ToDisplayString())
            //     // This is so we can use ComponentBase base class
            //     .Append(Constants.BlazorComponentsNamespace);

            var requiredNamespaceNames = _sourceFileSemanticModel.GetOriginalUsingNamespaces().Append(Constants.BlazorComponentsNamespace);

            requiredNamespaceNames = CodeSyntaxHelper.RemoveFrameworkUsings(requiredNamespaceNames);
            var allMethods = _originalDeclarationSyntax.DescendantNodes().OfType <MethodDeclarationSyntax>();
            var currentClassDeclaration = ((ClassDeclarationSyntax)_originalDeclarationSyntax)
                                          // Need to track methods so modifications can be made one after another
                                          .TrackNodes(allMethods)
                                          // Remove outdated base type references
                                          // TODO: Scan and remove specific base types in the future
                                          .ClearBaseTypes()
                                          // ComponentBase base class is required to use lifecycle events
                                          .AddBaseType(Constants.ComponentBaseClass);

            var orderedMethods = allMethods
                                 .Select(method => (method, LifecycleManagerService.CheckMethodPageLifecycleHook(method)))
                                 // Filter out non-lifecycle methods
                                 .Where(methodTuple => methodTuple.Item2 != null)
                                 // Order matters within new events so we order before processing
                                 .OrderBy(methodTuple =>
            {
                return((int)methodTuple.Item2);
            });

            // Remove old lifecycle methods, sort, and record their content
            foreach (var methodTuple in orderedMethods)
            {
                try
                {
                    // This records the statements in the proper collection
                    ProcessLifecycleEventMethod(methodTuple.Item1, (WebFormsPageLifecycleEvent)methodTuple.Item2);
                }
                catch (Exception e)
                {
                    LogHelper.LogError(e, $"{Rules.Config.Constants.WebFormsErrorTag}Failed to process WebForms lifecycle event method {methodTuple.Item1.Identifier} " +
                                       $"from {OriginalClassName} class at {_fullPath}");
                }

                // Refresh node before removing
                var currentMethodNode = currentClassDeclaration.GetCurrentNode(methodTuple.Item1);
                currentClassDeclaration = currentClassDeclaration.RemoveNode(currentMethodNode, SyntaxRemoveOptions.AddElasticMarker);
            }

            // Construct new lifecycle methods and add them to the class
            foreach (var newLifecycleEventKvp in _newLifecycleLines)
            {
                var newLifecycleEvent           = newLifecycleEventKvp.Key;
                var newLifecycleEventStatements = newLifecycleEventKvp.Value;

                try
                {
                    var newMethodDeclaration = ComponentSyntaxHelper.ConstructComponentLifecycleMethod(newLifecycleEvent, newLifecycleEventStatements);
                    currentClassDeclaration = currentClassDeclaration.AddMembers(newMethodDeclaration);
                }
                catch (Exception e)
                {
                    LogHelper.LogError(e, $"{Rules.Config.Constants.WebFormsErrorTag}Failed to construct new lifecycle event method for {newLifecycleEvent} Blazor event " +
                                       $"using {OriginalClassName} class at {_fullPath}");
                }
            }

            // If we need to make use of the dispose method, add the IDisposable
            // interface to the class, usings are fine as is because this come from
            // the System namespace
            if (_newLifecycleLines.ContainsKey(BlazorComponentLifecycleEvent.Dispose))
            {
                currentClassDeclaration = currentClassDeclaration.AddBaseType(Constants.DisposableInterface);
            }

            var namespaceNode = CodeSyntaxHelper.BuildNamespace(_originalClassSymbol.ContainingNamespace?.ToDisplayString(), currentClassDeclaration);
            var fileText      = CodeSyntaxHelper.GetFileSyntaxAsString(namespaceNode, CodeSyntaxHelper.BuildUsingStatements(requiredNamespaceNames));

            DoCleanUp();
            LogEnd();

            var result = new[] { new FileInformation(GetNewRelativePath(), Encoding.UTF8.GetBytes(fileText)) };

            return(Task.FromResult((IEnumerable <FileInformation>)result));
        }
Ejemplo n.º 14
0
 public void BuildUsingStatement_Correctly_Builds_Single_Using_Statement()
 {
     Assert.AreEqual(ExpectedTestReferencedNamespaceUsing1, CodeSyntaxHelper.BuildUsingStatement(TestReferencedNamespace1).NormalizeWhitespace().ToFullString());
 }
Ejemplo n.º 15
0
        public override Task <IEnumerable <FileInformation> > MigrateClassAsync()
        {
            LogStart();

            _metricsContext.CollectActionMetrics(WebFormsActionType.ClassConversion, ActionName);
            var className     = _originalDeclarationSyntax.Identifier.ToString();
            var namespaceName = _originalClassSymbol.ContainingNamespace?.ToDisplayString();

            // NOTE: Removed temporarily until usings can be better determined, at the moment, too
            // many are being removed
            //var requiredNamespaceNames = _sourceFileSemanticModel
            //    .GetNamespacesReferencedByType(_originalDeclarationSyntax)
            //    .Select(namespaceSymbol => namespaceSymbol.ToDisplayString());

            var requiredNamespaceNames = _sourceFileSemanticModel.GetOriginalUsingNamespaces()
                                         .Union(MiddlewareSyntaxHelper.RequiredNamespaces);

            requiredNamespaceNames = CodeSyntaxHelper.RemoveFrameworkUsings(requiredNamespaceNames);

            // Make this call once now so we don't have to keep doing it later
            var originalDescendantNodes = _originalDeclarationSyntax.DescendantNodes();
            var keepableMethods         = originalDescendantNodes.OfType <MethodDeclarationSyntax>();

            var processRequestMethod = keepableMethods.Where(method => LifecycleManagerService.IsProcessRequestMethod(method)).SingleOrDefault();
            IEnumerable <StatementSyntax> preHandleStatements;

            if (processRequestMethod != null)
            {
                preHandleStatements = processRequestMethod.Body.Statements.AddComment(string.Format(Constants.CodeOriginCommentTemplate, Constants.ProcessRequestMethodName));
                keepableMethods     = keepableMethods.Where(method => !method.IsEquivalentTo(processRequestMethod));
                _lifecycleManager.RegisterMiddlewareClass(WebFormsAppLifecycleEvent.RequestHandlerExecute, className, namespaceName, className, false);
            }
            else
            {
                preHandleStatements = new[]
                {
                    CodeSyntaxHelper.GetBlankLine().AddComment(string.Format(Constants.IdentificationFailureCommentTemplate, ProcessRequestDiscovery, InvokePopulationOperation))
                };
            }

            // We have completed any possible registration by this point
            _lifecycleManager.NotifyMiddlewareSourceProcessed();

            var fileText = string.Empty;

            try
            {
                var middlewareClassDeclaration = MiddlewareSyntaxHelper.ConstructMiddlewareClass(
                    middlewareClassName: className,
                    shouldContinueAfterInvoke: false,
                    constructorAdditionalStatements: originalDescendantNodes.OfType <ConstructorDeclarationSyntax>().FirstOrDefault()?.Body?.Statements,
                    preHandleStatements: preHandleStatements,
                    additionalFieldDeclarations: originalDescendantNodes.OfType <FieldDeclarationSyntax>(),
                    additionalPropertyDeclarations: originalDescendantNodes.OfType <PropertyDeclarationSyntax>(),
                    additionalMethodDeclarations: keepableMethods);

                var namespaceNode = CodeSyntaxHelper.BuildNamespace(namespaceName, middlewareClassDeclaration);
                fileText = CodeSyntaxHelper.GetFileSyntaxAsString(namespaceNode, CodeSyntaxHelper.BuildUsingStatements(requiredNamespaceNames));
            }
            catch (Exception e)
            {
                LogHelper.LogError(e, $"{Rules.Config.Constants.WebFormsErrorTag}Failed to construct new HttpHandler file content from {OriginalClassName} class at {_fullPath}");
            }

            DoCleanUp();
            LogEnd();

            // Http modules are turned into middleware and so we use a new middleware directory
            var newRelativePath = FilePathHelper.RemoveDuplicateDirectories(Path.Combine(Constants.MiddlewareDirectoryName, FilePathHelper.AlterFileName(_relativePath, newFileName: className)));
            // TODO: Potentially remove certain folders from beginning of relative path
            var result = new[] { new FileInformation(newRelativePath, Encoding.UTF8.GetBytes(fileText)) };

            return(Task.FromResult((IEnumerable <FileInformation>)result));
        }