Beispiel #1
0
        /// <summary>
        /// Gets a list of all classes in the project that qualify for transient dependency injection registration.
        /// </summary>
        /// <param name="project">Target project to register.</param>
        /// <param name="rejectedClassNames">The class names that are not allowed for dependency injection.</param>
        /// <param name="rejectedBaseClasses">The base classes not allowed for dependency injection.</param>
        /// <param name="targetInterfaceTypeForRegistration">The interfaces of a target type to use for registration, this includes inheriting the target type.</param>
        /// <returns></returns>
        public static async Task <IEnumerable <DependencyInjectionRegistrationInformation> > GetTransientClassesAsync(VsProject project,
                                                                                                                      IEnumerable <string> rejectedClassNames = null, IEnumerable <ModelLookupData> rejectedBaseClasses = null,
                                                                                                                      IEnumerable <ModelLookupData> targetInterfaceTypeForRegistration = null)
        {
            var result = new List <DependencyInjectionRegistrationInformation>();

            if (project == null)
            {
                return(result);
            }
            if (!project.HasChildren)
            {
                return(result);
            }

            var projectChildren = await project.GetChildrenAsync(true, true);

            var csSourceCodeDocuments = projectChildren
                                        .Where(m => m.ModelType == VisualStudioModelType.CSharpSource)
                                        .Cast <VsCSharpSource>();

            foreach (var csSourceCodeDocument in csSourceCodeDocuments)
            {
                var sourceCode = csSourceCodeDocument.SourceCode;
                if (sourceCode == null)
                {
                    continue;
                }
                if (!sourceCode.Classes.Any())
                {
                    continue;
                }

                var classes = sourceCode.Classes;
                foreach (var csClass in classes)
                {
                    var registration = IsTransientClass(csClass, rejectedClassNames, rejectedBaseClasses, targetInterfaceTypeForRegistration);

                    if (registration == null)
                    {
                        continue;
                    }

                    if (!result.Any(r => (r.ClassData?.Namespace == registration.ClassData?.Namespace && r.ClassData?.Name == registration.ClassData?.Name)))
                    {
                        result.Add(registration);
                    }
                }
                //result.AddRange(classes.Select(csClass => IsTransientClass(csClass, rejectedClassNames,
                //    rejectedBaseClasses, targetInterfaceTypeForRegistration)).Where(diInfo => diInfo != null));
            }

            return(result);
        }
        /// <summary>
        /// Extension method that searches a project for a C# class that exists in one of the projects documents.
        /// </summary>
        /// <param name="source">Source Project to search through</param>
        /// <param name="className">The name of the class to search for.</param>
        /// <param name="searchChildren">Flag that determines if the entire project should be searched or just the root of the project.</param>
        /// <returns>The first instance of the class or null.</returns>
        public static async Task <CsClass> FindClassAsync(this VsProject source, string className, bool searchChildren)
        {
            //Loading the visual studio models from the project and pre creating the source code files.
            var children = await source.GetChildrenAsync(searchChildren, true);

            //Extracting all the c# source code files from the returned models.
            var sourceCodeFiles = children.Where(p => p.ModelType.Equals(VisualStudioModelType.CSharpSource)).Cast <VsCSharpSource>();

            //Getting the first code file that contains the class. Returning either null or the found class.
            return(sourceCodeFiles.FirstOrDefault(s => s.SourceCode.Classes.Any(c => c.Name.Equals(className)))
                   ?.SourceCode.Classes.FirstOrDefault(c => c.Name.Equals(className)));
        }
Beispiel #3
0
        /// <summary>
        /// Loads all the classes that exist in the project from each code file found within the project. That qualify for dependency injection.
        /// </summary>
        /// <param name="project">The source project to get the classes from</param>
        /// <returns>The class models for all classes that qualify for transient dependency injection. If no classes are found an empty enumeration will be returned.</returns>
        public static async Task <IEnumerable <CsClass> > LoadInstanceProjectClassesForRegistrationAsync(VsProject project)
        {
            var result = new List <CsClass>();

            if (project == null)
            {
                return(result);
            }
            if (!project.HasChildren)
            {
                return(result);
            }

            try
            {
                var projectChildren = await project.GetChildrenAsync(true, true);

                var csSourceCodeDocuments = projectChildren
                                            .Where(m => m.ModelType == VisualStudioModelType.CSharpSource)
                                            .Cast <VsCSharpSource>();

                foreach (var csSourceCodeDocument in csSourceCodeDocuments)
                {
                    var sourceCode = csSourceCodeDocument.SourceCode;
                    if (sourceCode == null)
                    {
                        continue;
                    }
                    if (!sourceCode.Classes.Any())
                    {
                        continue;
                    }
                    var classes = sourceCode.Classes.Where(IsTransientClass).Where(c =>
                                                                                   result.All(r => $"{c.Namespace}.{c.Name}" != $"{r.Namespace}.{r.Name}"));

                    if (classes.Any())
                    {
                        result.AddRange(classes);
                    }
                }
            }
            catch (Exception unhandledError)
            {
                _logger.Error($"The following unhandled error occured while loading the classes to be added to dependency injection.",
                              unhandledError);
            }

            return(result);
        }
        /// <summary>
        /// Returns a list of non-source code documents from VsProject that have a matching extension.
        /// </summary>
        /// <param name="source">The source visual studio project to search.</param>
        /// <param name="extension">The file extension to search for</param>
        /// <param name="searchChildren">Flag that determines if nested project folders should also be searched for files.</param>
        /// <param name="excludeKnownExternalFolders">Flag that determines if a content filter should be applied.</param>
        /// <returns>List of documents that meet the criteria.</returns>
        public static async Task <IReadOnlyList <VsDocument> > GetDocumentsWithExtensionAsync(this VsProject source, string extension, bool searchChildren, bool excludeKnownExternalFolders)
        {
            //If no source is found return an empty list.
            if (source == null)
            {
                return(ImmutableList <VsDocument> .Empty);
            }

            //If no file extension is provided return an empty list.
            if (string.IsNullOrEmpty(extension))
            {
                return(ImmutableList <VsDocument> .Empty);
            }

            List <VsDocument> result = new List <VsDocument>();

            //Making sure we start with a period for the extension for searching purposes.
            if (!extension.StartsWith("."))
            {
                extension = $".{extension}";
            }

            //Calling the CodeFactory project system api to get the children of the project.
            var children = await source.GetChildrenAsync(searchChildren);

            //Filtering out to just
            var sourceFiles = children.Where(p => p.ModelType.Equals(VisualStudioModelType.Document))
                              .Cast <VsDocument>().Where(d => !d.IsSourceCode);

            return(sourceFiles.Where(s =>
            {
                //If we are excluding external folders just check for the extension.
                if (!excludeKnownExternalFolders)
                {
                    return s.Name.EndsWith(extension);
                }

                //Checking to make sure the file is not in the excluded list.
                var documentPath = s.Path;
                if (string.IsNullOrEmpty(documentPath))
                {
                    return false;
                }
                return !documentPath.ToLower().Contains("\\content\\") && s.Name.EndsWith(extension);
            }).ToImmutableList());
        }
        /// <summary>
        /// Extension method that searches C# source code files for a base class inheritance.
        /// </summary>
        /// <param name="source">The source visual studio project to search.</param>
        /// <param name="baseClassName">The name of the base class to search for.</param>
        /// <param name="searchChildren">Flag that determines if you search all child project folders under the project.</param>
        /// <returns>The target source code that meets the criteria or an empty list. </returns>
        public static async Task <IReadOnlyList <CsSource> > GetClassesThatInheritBaseAsync(this VsProject source, string baseClassName, bool searchChildren)
        {
            //If the project is not created return an empty list.
            if (source == null)
            {
                return(ImmutableList <CsSource> .Empty);
            }

            //Calling into the CodeFactory project system api to load all project items, will pre load the source code models.
            var children = await source.GetChildrenAsync(searchChildren, true);

            //Pulling out the list of all code files.
            var sourceCodeFiles = children.Where(p => p.ModelType.Equals(VisualStudioModelType.CSharpSource)).Cast <VsCSharpSource>();

            //Returning the code files that implement the target base class.
            return(sourceCodeFiles.Select(codeFile => codeFile.SourceCode)
                   .Where(sourceCode => sourceCode.Classes.Any(c => c.BaseClass.Name.Equals(baseClassName)))
                   .ToImmutableList());
        }
        /// <summary>
        /// Used to check a project model for the existence of a folder at the root level of a given name.  If the folder is
        /// missing - create it.
        /// </summary>
        /// <param name="source">The visual studio project that we are checking exists or creating.</param>
        /// <param name="folderName">The name of the folder to return.</param>
        /// <returns>The existing or created project folder.</returns>
        /// <exception cref="ArgumentNullException">Thrown if either provided parameter is not provided.</exception>
        public static async Task <VsProjectFolder> CheckAddFolder(this VsProject source, string folderName)
        {
            //Bounds checking to make sure all the data needed to get the folder returned is provided.
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (string.IsNullOrEmpty(folderName))
            {
                throw new ArgumentNullException(nameof(folderName));
            }

            //Calling the project system in CodeFactory and getting all the children in the root of the project.
            var projectFolders = await source.GetChildrenAsync(false);

            //Searching for the project folder, if it is not found will add the project folder to the root of the project.
            return(projectFolders.Where(m => m.ModelType == VisualStudioModelType.ProjectFolder)
                   .Where(m => m.Name.Equals(folderName))
                   .Cast <VsProjectFolder>()
                   .FirstOrDefault()
                   ?? await source.AddProjectFolderAsync(folderName));
        }
Beispiel #7
0
#pragma warning disable CS1998
        #region Overrides of VsCommandBase<VsProject>

        /// <summary>
        /// Validation logic that will determine if this command should be enabled for execution.
        /// </summary>
        /// <param name="result">The target model data that will be used to determine if this command should be enabled.</param>
        /// <returns>Boolean flag that will tell code factory to enable this command or disable it.</returns>
        public override async Task <bool> EnableCommandAsync(VsProject result)
        {
            //Result that determines if the the command is enabled and visible in the context menu for execution.
            bool isEnabled = false;

            try
            {
                var children = await result.GetChildrenAsync(true);

                if (children.Any(p => p.ModelType.Equals(VisualStudioModelType.ProjectFolder) && p.Name.Equals("Pages")))
                {
                    isEnabled = true;
                }
            }
            catch (Exception unhandledError)
            {
                _logger.Error($"The following unhandled error occured while checking if the solution explorer project command {commandTitle} is enabled. ",
                              unhandledError);
                isEnabled = false;
            }

            return(isEnabled);
        }
        /// <summary>
        /// Gets target classes that implement a target interface. It will skip classes that implement Page or HttpApplication.
        /// </summary>
        /// <param name="source">The project to search for the classes in.</param>
        /// <param name="interfaceName">The name of the interface to search for.</param>
        /// <param name="searchChildren">Flag to determine if sub folder should be searched or just the root project folder.</param>
        /// <returns>Readonly list of the found source code files with the target classes in them. or an empty list.</returns>
        public static async Task <IReadOnlyList <CsSource> > GetClassesThatImplementInterfaceAsync(this VsProject source, string interfaceName, bool searchChildren)
        {
            //Bounds check will return an empty list if no project was provided.
            if (source == null)
            {
                return(ImmutableList <CsSource> .Empty);
            }

            //Calls into the CodeFactory project system and gets the children of the supplied project. Will load all code files that support C# as CSharpSource files.
            var children = await source.GetChildrenAsync(searchChildren, true);

            //Extracting all the C# code files from the returned project data.
            var codeFiles = children.Where(p => p.ModelType.Equals(VisualStudioModelType.CSharpSource))
                            .Cast <VsCSharpSource>();

            //Collection all the code files that meet the criteria and returning the source code models for each.
            return(codeFiles.Where(s => s.SourceCode.Classes.Any(c =>
                                                                 (!c.BaseClass.Name.Equals("Page") && !c.BaseClass.Name.Equals("HttpApplication"))
                                                                 &&
                                                                 c.InheritedInterfaces.Any(x => x.Name.Equals(interfaceName))))
                   .Select(s => s.SourceCode)
                   .ToImmutableList());
        }
Beispiel #9
0
        /// <summary>
        /// Migrates logic class files over to the blazor server project.
        /// </summary>
        /// <param name="webFormProjectData">List of pre cached models for from the web form project.</param>
        /// <param name="webFormProject">The web forms project that we are migrating data from.</param>
        /// <param name="blazorServerProject">The blazor server project this is being migrated to.</param>
        public async Task MigrateLogic(IReadOnlyList <VsModel> webFormProjectData, VsProject webFormProject, VsProject blazorServerProject)
        {
            try
            {
                //Informing the dialog the migration step has started.
                await _statusTracking.UpdateStepStatusAsync(MigrationStepEnum.AppLogic, MigrationStatusEnum.Running);

                var childFiles = webFormProjectData.GetSourceCodeDocumentsAsync(true);

                //we don't want any known aspx/ascx files hitching a ride.  just plain vanilla *.cs files should qualify.
                var logicFiles = childFiles.Where(p => (!p.Name.ToLower().Contains("aspx.") && !p.Name.ToLower().Contains("ascx.") && !p.Name.ToLower().Contains("asax."))).ToList();

                //put logic files (using the file system into the target under the project root)
                foreach (VsCSharpSource sourceDocument in logicFiles)
                {
                    //look for specific files that are native to a WebForm app and skip them. ** TODO: move this to a config setting maybe?
                    if (sourceDocument.Name.ToLower().Contains("bundleconfig"))
                    {
                        continue;
                    }
                    if (sourceDocument.Name.ToLower().Contains("assemblyinfo"))
                    {
                        continue;
                    }
                    if (sourceDocument.Name.ToLower().Contains("startup"))
                    {
                        continue;
                    }
                    if (sourceDocument.Name.ToLower().Contains(".master"))
                    {
                        continue;
                    }

                    var logicDocument = await sourceDocument.LoadDocumentModelAsync();

                    var parentFolders = await logicDocument.GetParentFolders();

                    var source  = sourceDocument.SourceCode;
                    var docText = await logicDocument.GetDocumentContentAsStringAsync();

                    if (parentFolders.Count >= 1)
                    {
                        parentFolders.Reverse(); //The folders are returned in leaf-to-trunk so need to reverse the order for the next step.
                        VsProjectFolder createdFolder = null;

                        //deal with source folder hierarchy
                        for (int i = 0; i < parentFolders.Count; i++)
                        {
                            if (i > 0)
                            {
                                createdFolder = await createdFolder.CheckAddFolder(parentFolders[i].Name);
                            }
                            else
                            {
                                createdFolder = await blazorServerProject.CheckAddFolder(parentFolders[i].Name);
                            }
                        }

                        //copy the file.  We only really care about the most leaf/edge subfolder so its safe to use the creatdFolder variable here.
                        docText = docText.Replace(source.Classes.First().Namespace, $"{blazorServerProject.Name}.{createdFolder.Name}");

                        var targetFolderFiles = await createdFolder.GetChildrenAsync(false);

                        if (!targetFolderFiles.Any(c => c.Name.ToLower().Equals(logicDocument.Name.ToLower())))
                        {
                            await createdFolder.AddDocumentAsync(logicDocument.Name, docText);

                            //Updating the dialog with a status
                            await _statusTracking.UpdateCurrentStatusAsync(MigrationStepEnum.AppLogic, MessageTypeEnum.Information,
                                                                           $"Copied logic file: {logicDocument.Name} to project {blazorServerProject.Name} location: {Path.Combine(createdFolder.Path, logicDocument.Name)}");
                        }
                        else
                        {
                            await _statusTracking.UpdateCurrentStatusAsync(MigrationStepEnum.AppLogic, MessageTypeEnum.Warning,
                                                                           $"Logic file: {logicDocument.Name} already exists in target folder location: {Path.Combine(createdFolder.Path, logicDocument.Name)} and was skipped.");
                        }
                    }
                    else
                    {
                        var projFiles = await blazorServerProject.GetChildrenAsync(false);

                        if (!projFiles.Any(c => c.Name.ToLower().Equals(logicDocument.Name.ToLower())))
                        {
                            docText = docText.Replace(source.Classes.First().Namespace, $"{blazorServerProject.Name}");

                            var thing = await blazorServerProject.AddDocumentAsync(logicDocument.Name, docText);

                            //Updating the dialog with a status
                            await _statusTracking.UpdateCurrentStatusAsync(MigrationStepEnum.AppLogic, MessageTypeEnum.Information,
                                                                           $"Copied static file: {logicDocument.Name} to project {blazorServerProject.Name} location: {Path.Combine(blazorServerProject.Path, logicDocument.Name)}");
                        }
                        else
                        {
                            //Updating the dialog with a status
                            await _statusTracking.UpdateCurrentStatusAsync(MigrationStepEnum.AppLogic, MessageTypeEnum.Warning,
                                                                           $"Static file: {logicDocument.Name} already exists in project {blazorServerProject.Name} location: {Path.Combine(blazorServerProject.Path, logicDocument.Name)} and was skipped.");
                        }
                    }
                }

                //Completed the migration step informing the dialog.
                await _statusTracking.UpdateStepStatusAsync(MigrationStepEnum.AppLogic, MigrationStatusEnum.Passed);
            }
            catch (Exception unhandledError)
            {
                //Dumping the exception that occured directly into the status so the user can see what happened.
                await _statusTracking.UpdateCurrentStatusAsync(MigrationStepEnum.AppLogic, MessageTypeEnum.Error, $"The following unhandled error occured. '{unhandledError.Message}'");

                //Updating the status that the step failed
                await _statusTracking.UpdateStepStatusAsync(MigrationStepEnum.AppLogic, MigrationStatusEnum.Failed);
            }
        }
 /// <summary>
 /// Extension method that loads all <see cref="VsProjectFolder"/> , <see cref="VsDocument"/>, and <see cref="VsCSharpSource"/>
 /// </summary>
 public static async Task <IReadOnlyList <VsModel> > LoadAllProjectData(this VsProject source, bool loadSourceCode = true)
 {
     return(source != null ? await source.GetChildrenAsync(true, loadSourceCode) : ImmutableList <VsModel> .Empty);
 }
Beispiel #11
0
        /// <summary>
        /// Searches the root of a project for the dependency injection registration class. If it is not found will generate a new service registration class.
        /// </summary>
        /// <param name="source">The source project to load the registration class from.</param>
        /// <param name="className">The name of the class that is used for service registration. This will be set to the constant <see cref="NetConstants.DefaultDependencyInjectionClassName"/> this can be overwritten with a custom class name.</param>
        /// <param name="automatedRegistrationMethodName">The name of the automatic transient class registration method. This will be set to the constant <see cref="NetConstants.DefaultAutomaticTransientClassRegistrationMethodName"/> this can be overwritten with a custom method name. </param>
        /// <returns>The source code model for the registration class.</returns>
        public static async Task <CsSource> GetRegistrationClassAsync(VsProject source, string className     = NetConstants.DefaultDependencyInjectionClassName,
                                                                      string automatedRegistrationMethodName = NetConstants.DefaultAutomaticTransientClassRegistrationMethodName)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (!source.IsLoaded)
            {
                throw new CodeFactoryException("Project model was not loaded cannot load or create the registration class.");
            }
            if (string.IsNullOrEmpty(className))
            {
                throw new ArgumentNullException(nameof(className));
            }

            var projectFiles = await source.GetChildrenAsync(false, true);

            CsSource registrationSource = null;

            try
            {
                //Searching the projects root directory code files for the registration class
                if (projectFiles.Any())
                {
                    registrationSource = projectFiles.Where(f => f.ModelType == VisualStudioModelType.CSharpSource)
                                         .Cast <VsCSharpSource>().FirstOrDefault(s => s.SourceCode.Classes.Any(c => c.Name == className))
                                         ?.SourceCode;
                }

                //If no registration source code file was found then create a new registration class from scratch.
                if (registrationSource == null)
                {
                    var registrationClassCode = BuildNewRegistrationClass(source, className, automatedRegistrationMethodName);
                    if (registrationClassCode == null)
                    {
                        throw new CodeFactoryException("Could not generate the dependency injection registration source code");
                    }
                    string registrationClassFileName = $"{className}.cs";

                    var document = await source.AddDocumentAsync(registrationClassFileName, registrationClassCode);

                    registrationSource = await document.GetCSharpSourceModelAsync();
                }

                if (registrationSource == null)
                {
                    throw new CodeFactoryException("Cannot load the source code for the registration class.");
                }
            }
            catch (CodeFactoryException)
            {
                throw;
            }
            catch (Exception unhandledException)
            {
                throw new CodeFactoryException("An error occured while loading the registration class source code, cannot continue.", unhandledException);
            }

            return(registrationSource);
        }
        public async Task MigrateAspxFiles(IReadOnlyList <VsModel> webFormProjectData, VsProject webFormProject, VsProject blazorServerProject)
        {
            try
            {
                //Informing the dialog the migration step has started.
                await _statusTracking.UpdateStepStatusAsync(MigrationStepEnum.AspxPages, MigrationStatusEnum.Running);

                //Getting all the aspx & ascx files in the project.
                var aspxFiles = webFormProjectData.Where(p => p.ModelType == VisualStudioModelType.Document && (p.Name.EndsWith(".aspx") || p.Name.EndsWith(".ascx"))).Cast <VsDocument>();

                if (!aspxFiles.Any())
                {
                    await _statusTracking.UpdateCurrentStatusAsync(MigrationStepEnum.AspxPages, MessageTypeEnum.Warning,
                                                                   "No Aspx files were found in the web forms project. This step is finished.");

                    await _statusTracking.UpdateStepStatusAsync(MigrationStepEnum.AspxPages,
                                                                MigrationStatusEnum.Passed);

                    return;
                }

                //Migrate over the site.master layout pages.
                var layoutFiles = webFormProjectData.Where(p => p.Name.ToLower().Contains(".master"));
                var success     = await ConvertLayoutFiles(layoutFiles, blazorServerProject);

                //Calling into the CodeFactory project system and getting all the direct children of the project.
                var blazorRootModels = await blazorServerProject.GetChildrenAsync(false);

                //Getting the pages folder from the blazor project.
                var blazorPagesFolder = blazorRootModels.FirstOrDefault(m =>
                                                                        m.ModelType == VisualStudioModelType.ProjectFolder & m.Name.ToLower().Equals("pages")) as VsProjectFolder;

                //If the pages folder was not found fail this step and return.
                if (blazorPagesFolder == null)
                {
                    await _statusTracking.UpdateCurrentStatusAsync(MigrationStepEnum.AspxPages, MessageTypeEnum.Error,
                                                                   "No pages folder was found in the blazor project, cannot continue the aspx file conversion.");

                    await _statusTracking.UpdateStepStatusAsync(MigrationStepEnum.AspxPages,
                                                                MigrationStatusEnum.Failed);

                    return;
                }

                //Call the CodeFactory project system to get all the current children of the pages project folder.
                var pagesFolderModels = await blazorPagesFolder.GetChildrenAsync(true);

                //Filtering out everything but documents.
                var pages = pagesFolderModels.Where(m => m.ModelType == VisualStudioModelType.Document)
                            .Cast <VsDocument>();

                int collect = 0;

                //Processing each aspx file.
                foreach (VsDocument aspxFile in aspxFiles)
                {
                    collect++;

                    //Getting the formatted names that will be used in migrating the ASPX file and its code behind to the blazor project.
                    string targetFileNameNoExtension   = Path.GetFileNameWithoutExtension(aspxFile.Path);
                    string aspxCodeBehindFileName      = $"{targetFileNameNoExtension}.aspx.cs";
                    string ascxCodeBehindFileName      = $"{targetFileNameNoExtension}.axcs.cs";
                    string razorPageFileName           = $"{targetFileNameNoExtension}.razor";
                    string razorPageCodeBehindFileName = $"{targetFileNameNoExtension}.razor.cs";

                    //Searching for an existing razor page. We will delete razor pages and recreate them.
                    var currentRazorPage = pages.FirstOrDefault(p => p.Path.ToLower().EndsWith(razorPageFileName.ToLower()));

                    if (currentRazorPage != null)
                    {
                        //Razor page was found removing the razor page.
                        bool removedPage = await currentRazorPage.DeleteAsync();

                        if (removedPage)
                        {
                            await _statusTracking.UpdateCurrentStatusAsync(MigrationStepEnum.AspxPages,
                                                                           MessageTypeEnum.Information, $"Removed the razor page {razorPageFileName}");

                            var currentRazorPageCodeBehind = pages.FirstOrDefault(p => p.Path.ToLower().EndsWith(razorPageCodeBehindFileName.ToLower()));

                            if (currentRazorPageCodeBehind != null)
                            {
                                if (File.Exists(currentRazorPageCodeBehind.Path))
                                {
                                    bool removedCodeBehind = await currentRazorPageCodeBehind.DeleteAsync();

                                    if (removedCodeBehind)
                                    {
                                        await _statusTracking.UpdateCurrentStatusAsync(MigrationStepEnum.AspxPages,
                                                                                       MessageTypeEnum.Information,
                                                                                       $"Removed the razor page code behind file {razorPageCodeBehindFileName}");
                                    }
                                    else
                                    {
                                        await _statusTracking.UpdateCurrentStatusAsync(MigrationStepEnum.AspxPages,
                                                                                       MessageTypeEnum.Error,
                                                                                       $"Could not remove the razor page code behind file {razorPageCodeBehindFileName}.The target ASPX file will not be migrated.");

                                        continue;
                                    }
                                }
                            }
                        }
                        else
                        {
                            await _statusTracking.UpdateCurrentStatusAsync(MigrationStepEnum.AspxPages,
                                                                           MessageTypeEnum.Error,
                                                                           $"Could not remove the razor page {razorPageFileName}.The target ASPX file will not be migrated.");

                            continue;
                        }
                    }

                    VsCSharpSource CodeBehindSource = null;
                    if (aspxFile.Path.Contains("ascx"))
                    {
                        //Getting the code behind file that supports the current aspx page.
                        CodeBehindSource = webFormProjectData
                                           .Where(m => m.ModelType == VisualStudioModelType.CSharpSource).Cast <VsCSharpSource>()
                                           .FirstOrDefault(s => s.SourceCode.SourceDocument.ToLower().EndsWith(ascxCodeBehindFileName.ToLower())) as VsCSharpSource;
                    }

                    //Getting the code behind file that supports the current aspx page.
                    CodeBehindSource = webFormProjectData
                                       .Where(m => m.ModelType == VisualStudioModelType.CSharpSource).Cast <VsCSharpSource>()
                                       .FirstOrDefault(s => s.SourceCode.SourceDocument.ToLower().EndsWith(aspxCodeBehindFileName.ToLower())) as VsCSharpSource;

                    //Converting the aspx page and the code behind file if it was found.
                    await ConvertAspxPage(aspxFile, blazorServerProject, blazorPagesFolder, CodeBehindSource);

                    if (collect == 4)
                    {
                        GC.Collect();
                        collect = 0;
                    }
                }

                //Completed the migration step informing the dialog.
                await _statusTracking.UpdateStepStatusAsync(MigrationStepEnum.AspxPages, MigrationStatusEnum.Passed);
            }
            catch (Exception unhandledError)
            {
                //Dumping the exception that occured directly into the status so the user can see what happened.
                await _statusTracking.UpdateCurrentStatusAsync(MigrationStepEnum.AspxPages, MessageTypeEnum.Error, $"The following unhandled error occured. '{unhandledError.Message}'");

                //Updating the status that the step failed
                await _statusTracking.UpdateStepStatusAsync(MigrationStepEnum.AspxPages, MigrationStatusEnum.Failed);
            }
        }
        public async Task MigrateSingleASPXFile(VsDocument aspxSourcefile, VsProject blazorServerProject)
        {
            try
            {
                //VsCSharpSource aspxCodeBehindFile
                //Getting the formatted names that will be used in migrating the ASPX file and its code behind to the blazor project.
                string targetFileNameNoExtension   = Path.GetFileNameWithoutExtension(aspxSourcefile.Path);
                string aspxCodeBehindFileName      = $"{targetFileNameNoExtension}.aspx.cs";
                string razorPageFileName           = $"{targetFileNameNoExtension}.razor";
                string razorPageCodeBehindFileName = $"{targetFileNameNoExtension}.razor.cs";

                //Calling into the CodeFactory project system and getting all the direct children of the project.
                var blazorRootModels = await blazorServerProject.GetChildrenAsync(false);

                //Getting the pages folder from the blazor project.
                var blazorPagesFolder = blazorRootModels.FirstOrDefault(m =>
                                                                        m.ModelType == VisualStudioModelType.ProjectFolder & m.Name.ToLower().Equals("pages")) as VsProjectFolder;

                //If the pages folder was not found fail this step and return.
                if (blazorPagesFolder == null)
                {
                    await _statusTracking.UpdateCurrentStatusAsync(MigrationStepEnum.AspxPages, MessageTypeEnum.Error,
                                                                   "No pages folder was found in the blazor project, cannot continue the aspx file conversion.");

                    return;
                }

                //Call the CodeFactory project system to get all the current children of the pages project folder.
                var pagesFolderModels = await blazorPagesFolder.GetChildrenAsync(true);

                //Filtering out everything but documents.
                var pages = pagesFolderModels.Where(m => m.ModelType == VisualStudioModelType.Document)
                            .Cast <VsDocument>();

                //Searching for an existing razor page. We will delete razor pages and recreate them.
                var currentRazorPage = pages.FirstOrDefault(p => p.Path.ToLower().EndsWith(razorPageFileName.ToLower()));

                if (currentRazorPage != null)
                {
                    //Razor page was found removing the razor page.
                    bool removedPage = await currentRazorPage.DeleteAsync();

                    if (removedPage)
                    {
                        await _statusTracking.UpdateCurrentStatusAsync(MigrationStepEnum.AspxPages,
                                                                       MessageTypeEnum.Information, $"Removed the razor page {razorPageFileName}");

                        var currentRazorPageCodeBehind = pages.FirstOrDefault(p => p.Path.ToLower().EndsWith(razorPageCodeBehindFileName.ToLower()));

                        if (currentRazorPageCodeBehind != null)
                        {
                            if (File.Exists(currentRazorPageCodeBehind.Path))
                            {
                                bool removedCodeBehind = await currentRazorPageCodeBehind.DeleteAsync();

                                if (removedCodeBehind)
                                {
                                    await _statusTracking.UpdateCurrentStatusAsync(MigrationStepEnum.AspxPages,
                                                                                   MessageTypeEnum.Information,
                                                                                   $"Removed the razor page code behind file {razorPageCodeBehindFileName}");
                                }
                                else
                                {
                                    await _statusTracking.UpdateCurrentStatusAsync(MigrationStepEnum.AspxPages,
                                                                                   MessageTypeEnum.Error,
                                                                                   $"Could not remove the razor page code behind file {razorPageCodeBehindFileName}.The target ASPX file will not be migrated.");

                                    return;
                                }
                            }
                        }
                    }
                    else
                    {
                        await _statusTracking.UpdateCurrentStatusAsync(MigrationStepEnum.AspxPages,
                                                                       MessageTypeEnum.Error,
                                                                       $"Could not remove the razor page {razorPageFileName}.The target ASPX file will not be migrated.");

                        return;
                    }
                }

                var aspxChildren = await aspxSourcefile.GetChildrenAsync(true);

                var codeBehindFile = aspxChildren
                                     .Where(c => (c.IsSourceCode == true) && (c.SourceType == SourceCodeType.CSharp)).FirstOrDefault();

                //Converting the aspx page and the code behind file if it was found.
                await ConvertAspxPage(aspxSourcefile, blazorServerProject, blazorPagesFolder, null, codeBehindFile);

                await _statusTracking.UpdateMigrationFinishedAsync();
            }
            catch (Exception unhandledError)
            {
                //Dumping the exception that occured directly into the status so the user can see what happened.
                await _statusTracking.UpdateCurrentStatusAsync(MigrationStepEnum.AspxPages, MessageTypeEnum.Error, $"The following unhandled error occured. '{unhandledError.Message}'");
            }
        }