示例#1
0
        private void GetActions(HtmlNode node, HtmlNode parent)
        {
            string controlConverterType = "NonWebFormsControl";

            if (SupportedControls.ControlRulesMap.ContainsKey(node.Name))
            {
                var conversionAction = new ControlConversionAction(node, parent, SupportedControls.ControlRulesMap[node.Name]);
                controlConverterType = conversionAction.ControlConverter.GetType().Name;
                _controlActions.Add(conversionAction);
            }
            else if (SupportedControls.UserControls.UserControlRulesMap.ContainsKey(node.Name))
            {
                var conversionAction = new ControlConversionAction(node, parent, SupportedControls.UserControls.UserControlRulesMap[node.Name]);
                controlConverterType = conversionAction.ControlConverter.GetType().Name;
                _controlActions.Add(conversionAction);
            }
            else
            {
                Match aspControlTagRegex = AspControlsRegex.Match(node.Name);
                if (aspControlTagRegex.Success)
                {
                    controlConverterType = UnSupportedControlConverter;
                }
            }
            _metricsContext.CollectActionMetrics(WebFormsActionType.ControlConversion, controlConverterType, node.Name);
        }
        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));
        }
示例#3
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));
        }
示例#4
0
        public override Task <IEnumerable <FileInformation> > MigrateFileAsync()
        {
            LogStart();
            _metricsContext.CollectActionMetrics(WebFormsActionType.FileConversion, ChildActionType);

            // TODO: Extract info from project files and
            // call _blazorWorkspaceManager.CreateProjectFile
            // and _webFormsWorkspaceManager.CreateProjectFile

            // TODO: Retrieve cancellation token from thread manager service
            // _blazorWorkspaceManager.WaitUntilAllDocumentsInWorkspace(token);

            // TODO: Extract accumulated project info from
            // workspace and use it to build the actual
            // project file

            string newCsProjContent = GenerateProjectFileContents(_projectAnalyzer.ProjectResult,
                                                                  _projectAnalyzer.ProjectConfiguration, _projectAnalyzer.ProjectReferences, _projectAnalyzer.MetaReferences);

            FileInformation fi = new FileInformation(FilePathHelper.RemoveDuplicateDirectories(RelativePath), Encoding.UTF8.GetBytes(newCsProjContent));

            var fileList = new List <FileInformation>()
            {
                fi
            };

            DoCleanUp();
            LogEnd();

            return(Task.FromResult((IEnumerable <FileInformation>)fileList));
        }
示例#5
0
        public static string ConstructBlazorDirectives(string content, string originalFilePath, string projectName, ViewImportService viewImportService, WebFormMetricContext metricContext)
        {
            var directiveName      = DirectiveNameRegex.Match(content).Groups[DirectiveNameRegexGroupName].Value;
            var directiveConverter = SupportedControls.DirectiveRulesMap.ContainsKey(directiveName) ?
                                     SupportedControls.DirectiveRulesMap[directiveName] : SupportedControls.DefaultDirectiveConverter;

            metricContext.CollectActionMetrics(WebFormsActionType.DirectiveConversion, directiveName + "DirectiveConverter");

            return(directiveConverter.ConvertDirective(directiveName, content.Trim(), originalFilePath, projectName, viewImportService));
        }
示例#6
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)) });
        }
示例#7
0
        public override Task <IEnumerable <FileInformation> > MigrateFileAsync()
        {
            LogStart();
            _metricsContext.CollectActionMetrics(WebFormsActionType.FileConversion, ChildActionType);
            FileInformation fi = new FileInformation(FilePathHelper.RemoveDuplicateDirectories(RelativePath), File.ReadAllBytes(FullPath));

            var fileList = new List <FileInformation>();

            fileList.Add(fi);

            DoCleanUp();
            LogEnd();

            return(Task.FromResult((IEnumerable <FileInformation>)fileList));
        }
示例#8
0
        public override async Task <IEnumerable <FileInformation> > MigrateFileAsync()
        {
            LogStart();
            _metricsContext.CollectActionMetrics(WebFormsActionType.FileConversion, ChildActionType);

            // Need to have ToList call here to enumerate the collection and ensure class
            // converters are running before we retire this file converter task
            var classMigrationTasks = _classConverters.Select(converter => converter.MigrateClassAsync()).ToList();

            // We want to do our cleanup now because from this point on all migration tasks
            // are done by class converters and we want to make sure that we retire the task
            // related to this file converter before we await
            DoCleanUp();

            var allMigrationTasks = Task.WhenAll(classMigrationTasks);

            try
            {
                await allMigrationTasks;
            }
            // We don't provide a reference for the thrown exception here because await auto-
            // unwraps aggregate exceptions and throws only the first encountered exception
            catch
            {
                // We access allMigrationTasks.Exception instead to provide the original AggregateException
                var allExceptions = allMigrationTasks.Exception.Flatten().InnerExceptions;

                foreach (Exception e in allExceptions)
                {
                    LogHelper.LogError(e, $"{Rules.Config.Constants.WebFormsErrorTag}Failed to migrate class");
                }
            }

            var result = classMigrationTasks.Where(t => t.Status == TaskStatus.RanToCompletion).SelectMany(t => t.Result);

            LogEnd();

            return(result);
        }
示例#9
0
        public override Task <IEnumerable <FileInformation> > MigrateFileAsync()
        {
            LogStart();
            _metricsContext.CollectActionMetrics(WebFormsActionType.FileConversion, ChildActionType);

            string filename = Path.GetFileName(RelativePath);
            var    fileList = new List <FileInformation>();

            //Currently only handles web.config, package.config handled by ProjectFileConverter, others not handled
            if (filename.Equals(WebConfigFile, StringComparison.InvariantCultureIgnoreCase))
            {
                //ProjectType WebForms doesn't really exist yet, but can be added for more specific configuration
                ConfigMigrate configMigrate  = new ConfigMigrate(FullPath, ProjectType.WebForms);
                var           migratedString = configMigrate.WebformsWebConfigMigrateHelper();

                string newPath = FilePathHelper.RemoveDuplicateDirectories(Path.Combine(_relativeDirectory, Constants.AppSettingsFileName));
                fileList.Add(new FileInformation(newPath, Encoding.UTF8.GetBytes(migratedString)));
            }

            DoCleanUp();
            LogEnd();

            return(Task.FromResult((IEnumerable <FileInformation>)fileList));
        }
示例#10
0
        public override Task <IEnumerable <FileInformation> > MigrateFileAsync()
        {
            LogStart();
            _metricsContext.CollectActionMetrics(WebFormsActionType.FileConversion, ChildActionType);
            // We want to add the relative path to _Host.cshtml before
            // prepending wwwroot/ because the web root folder is ignored
            // when fetching static files
            if (RelativePath.EndsWith(Constants.StyleSheetFileExtension, StringComparison.InvariantCultureIgnoreCase))
            {
                _hostPageService.AddStyleSheetPath(RelativePath);
            }

            var newPath  = FilePathHelper.RemoveDuplicateDirectories(Path.Combine(Constants.WebRootDirectoryName, RelativePath));
            var fullPath = Path.Combine(ProjectPath, RelativePath);

            FileInformation fi = new FileInformation(newPath, File.ReadAllBytes(fullPath));

            var fileList = new[] { fi };

            DoCleanUp();
            LogEnd();

            return(Task.FromResult((IEnumerable <FileInformation>)fileList));
        }
示例#11
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));
        }
示例#12
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));
        }