Exemplo n.º 1
0
        /// <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(VsCSharpSource result)
        {
            //Result that determines if the the command is enabled and visible in the context menu for execution.
            bool isEnabled = false;

            try
            {
                if (!result.IsLoaded)
                {
                    return(false);
                }
                if (!result.SourceCode.Classes.Any())
                {
                    return(false);
                }
                isEnabled = result.SourceCode.Classes.Any(c => ContractHelper.GetSubscriptions(c) != null);
            }
            catch (Exception unhandledError)
            {
                _logger.Error($"The following unhandled error occured while checking if the solution explorer C# document command {commandTitle} is enabled. ",
                              unhandledError);
                isEnabled = false;
            }

            return(isEnabled);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Gets the contract source file, if one does not exist it will create the partial class file.
        /// </summary>
        /// <param name="source">The visual studio source file to search.</param>
        /// <param name="sourceClass">The target class that contains the contract.</param>
        /// <returns>The target source code or null if it could not be created.</returns>
        public static async Task <CsSource> GetContractSourceFileAsync(VsCSharpSource source, CsClass sourceClass)
        {
            if (source == null)
            {
                return(null);
            }
            if (sourceClass == null)
            {
                return(null);
            }

            var contractFile = GetContractFilePath(sourceClass);

            CsSource result = null;

            if (contractFile.hasFile)
            {
                result = await source.GetCsSourceDocumentFromParent(contractFile.filePath);
            }
            else
            {
                var manager            = source.SourceCode.LoadNamespaceManager(sourceClass.Namespace);
                var partialClassSource = CSharpSourceGenerationCommon.GeneratePartialClass(sourceClass, manager);

                if (string.IsNullOrEmpty(partialClassSource))
                {
                    throw new CodeFactoryException($"Could not generated partial class definition for class {sourceClass.Name}");
                }

                result = await source.AddCSharpCodeFileToParentAsync(partialClassSource,
                                                                     Path.GetFileName(contractFile.filePath));
            }

            return(result);
        }
        /// <summary>
        /// Extension method designed to look in the parent project folder, or project of the current source document and find a target code file in that location.
        /// </summary>
        /// <param name="source">The source model.</param>
        /// <param name="targetFilePath">The fully qualified path to the target model.</param>
        /// <returns>The loaded source or null if the source could not be loaded.</returns>
        public static async Task <CsSource> GetCsSourceDocumentFromParent(this VsCSharpSource source, string targetFilePath)
        {
            if (source == null)
            {
                return(null);
            }
            if (string.IsNullOrEmpty(targetFilePath))
            {
                return(null);
            }

            var parentData = await source.GetCSharpSourceDocumentParentAsync();

            var parent = parentData.ParentModel;

            if (parent == null)
            {
                throw new CodeFactoryException("Source document is not hosted in a project or project folder.");
            }

            VsCSharpSource sourceDocument = null;

            if (!parentData.IsProject)
            {
                var parentFolder = parent as VsProjectFolder;

                if (parentFolder == null)
                {
                    throw new CodeFactoryException("Cannot access the parent of the source code document");
                }

                var children = await parentFolder.GetChildrenAsync(false, true);

                sourceDocument = children.Where(c => c.ModelType == VisualStudioModelType.CSharpSource)
                                 .Cast <VsCSharpSource>()
                                 .FirstOrDefault(s => s.SourceCode.SourceDocument == targetFilePath);
            }
            else
            {
                var parentProject = parent as VsProject;

                if (parentProject == null)
                {
                    throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription");
                }

                var children = await parentProject.GetChildrenAsync(false, true);

                sourceDocument = children.Where(c => c.ModelType == VisualStudioModelType.CSharpSource)
                                 .Cast <VsCSharpSource>()
                                 .FirstOrDefault(s => s.SourceCode.SourceDocument == targetFilePath);;
            }

            return(sourceDocument?.SourceCode);
        }
        /// <summary>
        /// Code factory framework calls this method when the command has been executed.
        /// </summary>
        /// <param name="result">The code factory model that has generated and provided to the command to process.</param>
        public override async Task ExecuteCommandAsync(VsCSharpSource result)
        {
            try
            {
                //Get the missing members and the target class or classes they are to be loaded into.
                var missingMembers = result.SourceMissingInterfaceMembers();

                //Getting the hosting project for the command.
                var hostingProject = await result.GetHostingProjectAsync();

                //If no hosting project can be found this command should not be executed.
                if (hostingProject == null)
                {
                    return;
                }

                //Determining if the project supports the asp.net extensions for the common delivery framework
                bool supportCDFAspnet = await hostingProject.HasReferenceLibraryAsync(AspNetCoreConstants.CommonDeliveryFrameworkAspNetLibraryName);

                //If the logging abstraction library is loaded then enable logging for members.
                var enableLogging = true;

                //Bounds checking will be supported for this command
                bool boundsChecking = true;

                //Async keyword will be used for this command
                bool supportAsync = true;

                //Process each class missing members
                foreach (var missingMember in missingMembers)
                {
                    //Get the container model that has missing members.
                    var container = missingMember.Key;

                    //Confirming the container is a class if not continue
                    if (container.ContainerType != CsContainerType.Class)
                    {
                        continue;
                    }

                    var targetClass = container as CsClass;

                    //Adding the missing members
                    await ClassMemberManagement.AddMembersToClassWithCDFSupportAsync(result.SourceCode, targetClass, missingMember.Value, boundsChecking, enableLogging, supportAsync, supportCDFAspnet);
                }
            }
            catch (Exception unhandledError)
            {
                _logger.Error($"The following unhandled error occured while executing the solution explorer C# document command {commandTitle}. ",
                              unhandledError);
            }
        }
        /// <summary>
        /// Adds a new C# document to the parent project or folder of the current c# document.
        /// </summary>
        /// <param name="source">C# source document.</param>
        /// <param name="sourceCode">The source code to be added to the new code file.</param>
        /// <param name="targetFileName">The target file name of the new document.</param>
        /// <returns></returns>
        public static async Task <CsSource> AddCSharpCodeFileToParentAsync(this VsCSharpSource source, string sourceCode,
                                                                           string targetFileName)
        {
            if (source == null)
            {
                throw new CodeFactoryException("No visual studio c# source was provided cannot add C# code file.");
            }
            if (string.IsNullOrEmpty(targetFileName))
            {
                throw new CodeFactoryException("No filename was provided cannot add the C# code file.");
            }

            var parent = await source.GetCSharpSourceDocumentParentAsync();

            if (parent.ParentModel == null)
            {
                throw new CodeFactoryException("No project or project folder was found, cannot add the C# code file.");
            }


            VsDocument document = null;

            if (parent.IsProject)
            {
                var project = parent.ParentModel as VsProject;

                if (project == null)
                {
                    throw new CodeFactoryException("Could load the project information, cannot add the C# code file.");
                }

                document = await project.AddDocumentAsync(targetFileName, sourceCode);
            }
            else
            {
                var projectFolder = parent.ParentModel as VsProjectFolder;

                if (projectFolder == null)
                {
                    throw new CodeFactoryException("Could load the project folder information, cannot add the C# code file.");
                }

                document = await projectFolder.AddDocumentAsync(targetFileName, sourceCode);
            }

            var csDocument = await document.GetCSharpSourceModelAsync();

            return(csDocument);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Gets the contracts main class file. This will force a model reload.
        /// </summary>
        /// <param name="source">Visual studio source file to start from.</param>
        /// <param name="sourceClass">The target class to check for.</param>
        /// <returns>The source file or null if it could not before loaded. </returns>
        public static async Task <CsSource> GetContractBaseFileAsync(VsCSharpSource source, CsClass sourceClass)
        {
            if (source == null)
            {
                return(null);
            }
            if (sourceClass == null)
            {
                return(null);
            }

            var contractFile = GetContractFilePath(sourceClass);

            var baseFilePath = contractFile.filePath.Replace(WPFConstants.DefaultContractSuffix, ".cs");

            return(await source.GetCsSourceDocumentFromParent(baseFilePath));
        }
Exemplo n.º 7
0
        /// <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(VsCSharpSource result)
        {
            //Result that determines if the the command is enabled and visible in the context menu for execution.
            bool isEnabled = false;

            try
            {
                isEnabled = result.SourceCode.SourceMissingInterfaceMembers() != null;
            }
            catch (Exception unhandledError)
            {
                _logger.Error($"The following unhandled error occured while checking if the solution explorer C# document command {commandTitle} is enabled. ",
                              unhandledError);
                isEnabled = false;
            }

            return(isEnabled);
        }
        /// <summary>
        /// Determines if the source code has classes that implement controller base.
        /// </summary>
        /// <param name="source">Source code to evaluate.</param>
        /// <returns>True if found, or false if not</returns>
        public static bool IsControllerSourceCode(VsCSharpSource source)
        {
            if (source == null)
            {
                return(false);
            }
            if (!source.IsLoaded)
            {
                return(false);
            }
            var classes = source.SourceCode.Classes;

            if (classes == null)
            {
                return(false);
            }
            return(classes.Any(IsController));
        }
        public override async Task <bool> EnableCommandAsync(VsCSharpSource result)
        {
            //Result that determines if the the command is enabled and visible in the context menu for execution.
            bool isEnabled = false;

            try
            {
                //Determines if there are missing members in the source document
                var missingMembers = result.SourceMissingInterfaceMembers();


                //If missing members are found display the command.
                isEnabled = missingMembers.Any();

                if (isEnabled)
                {
                    var projectData = await result.GetHostingProjectAsync();

                    var hasLogging = await projectData.HasReferenceLibraryAsync(AspNetCoreConstants.MicrosoftLoggerLibraryName);

                    var hasCDF = await projectData.HasReferenceLibraryAsync(AspNetCoreConstants.CommonDeliveryFrameworkLibraryName);

                    if (hasLogging & hasCDF)
                    {
                        isEnabled = false;
                    }
                }
            }
            catch (Exception unhandledError)
            {
                _logger.Error($"The following unhandled error occured while checking if the solution explorer C# document command {commandTitle} is enabled. ",
                              unhandledError);
                isEnabled = false;
            }

            return(isEnabled);
        }
Exemplo n.º 10
0
        /// <summary>
        /// Code factory framework calls this method when the command has been executed.
        /// </summary>
        /// <param name="result">The code factory model that has generated and provided to the command to process.</param>
        public override async Task ExecuteCommandAsync(VsCSharpSource result)
        {
            try
            {
                var sourceCode = result.SourceCode;

                var classes = sourceCode.Classes;

                foreach (var csClass in classes)
                {
                    if (!(sourceCode.GetModel(csClass.LookupPath) is CsClass currentClass))
                    {
                        throw new CodeFactoryException("Cannot access class data cannot update subscriptions");
                    }

                    var subscriptions = ContractHelper.GetSubscriptions(currentClass);
                    if (subscriptions == null)
                    {
                        continue;
                    }

                    if (!subscriptions.Any())
                    {
                        continue;
                    }
                    foreach (var subscription in subscriptions)
                    {
                        sourceCode = await UpdateSubscriptionAsync(subscription, currentClass, result);
                    }
                }
            }
            catch (Exception unhandledError)
            {
                _logger.Error($"The following unhandled error occured while executing the solution explorer C# document command {commandTitle}. ",
                              unhandledError);
            }
        }
Exemplo n.º 11
0
        private async Task <CsSource> UpdateSubscriptionAsync(CsField subscriptionField, CsClass sourceClass, VsCSharpSource source)
        {
            SourceFormatter formatter        = new SourceFormatter();
            string          injectSourceCode = null;

            var contract = subscriptionField.DataType.GetInterfaceModel();

            if (contract == null)
            {
                return(null);
            }

            CsSource sourceCode = source.SourceCode;

            try
            {
                CsClass currentClass = sourceClass;

                var events = contract.Events;

                var subscribePath = ContractHelper.GetSubscribeFilePath(currentClass);


                if (!subscribePath.hasFile)
                {
                    var manager = sourceCode.LoadNamespaceManager(sourceClass.Namespace);

                    var parent = await source.GetParentAsync();

                    if (parent == null)
                    {
                        throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription");
                    }

                    VsDocument generatedDocument  = null;
                    string     partialClassSource = CSharpSourceGenerationCommon.GeneratePartialClass(currentClass, manager);
                    if (parent.ModelType == VisualStudioModelType.ProjectFolder)
                    {
                        var parentFolder = parent as VsProjectFolder;

                        if (parentFolder == null)
                        {
                            throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription");
                        }

                        generatedDocument = await parentFolder.AddDocumentAsync(Path.GetFileName(subscribePath.filePath),
                                                                                partialClassSource);
                    }
                    else
                    {
                        var parentProject = parent as VsProject;

                        if (parentProject == null)
                        {
                            throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription");
                        }

                        generatedDocument = await parentProject.AddDocumentAsync(subscribePath.filePath,
                                                                                 partialClassSource);
                    }
                    sourceCode = await generatedDocument.GetCSharpSourceModelAsync();

                    sourceCode = await sourceCode.AddMissingNamespaces(contract.Events, currentClass.Namespace);

                    currentClass = sourceCode.GetModel(currentClass.LookupPath) as CsClass;

                    if (currentClass == null)
                    {
                        throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription");
                    }
                }
                else
                {
                    var parent = await source.GetParentAsync();

                    VsCSharpSource sourceDocument = null;
                    if (parent.ModelType == VisualStudioModelType.ProjectFolder)
                    {
                        var parentFolder = parent as VsProjectFolder;

                        if (parentFolder == null)
                        {
                            throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription");
                        }

                        var children = await parentFolder.GetChildrenAsync(false, true);

                        sourceDocument = children.Where(c => c.ModelType == VisualStudioModelType.CSharpSource)
                                         .Cast <VsCSharpSource>()
                                         .FirstOrDefault(s => s.SourceCode.SourceDocument == subscribePath.filePath);
                    }
                    else
                    {
                        var parentProject = parent as VsProject;

                        if (parentProject == null)
                        {
                            throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription");
                        }

                        var children = await parentProject.GetChildrenAsync(false, true);

                        sourceDocument = children.Where(c => c.ModelType == VisualStudioModelType.CSharpSource)
                                         .Cast <VsCSharpSource>()
                                         .FirstOrDefault(s => s.SourceCode.SourceDocument == subscribePath.filePath);;
                    }

                    if (sourceDocument == null)
                    {
                        throw new CodeFactoryException("Could load the contract document.");
                    }

                    sourceCode = sourceDocument.SourceCode;

                    sourceCode = await sourceCode.AddMissingNamespaces(contract.Events, currentClass.Namespace);

                    currentClass = sourceCode.GetModel(currentClass.LookupPath) as CsClass;
                    if (currentClass == null)
                    {
                        throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription");
                    }
                }

                var namespaceManager = sourceCode.LoadNamespaceManager(currentClass.Namespace);

                foreach (var contractEvent in contract.Events)
                {
                    var eventHandlerName =
                        CSharpSourceGenerationWPF.GenerateContractEventHandlerMethodName(subscriptionField, contractEvent);

                    if (eventHandlerName == null)
                    {
                        throw new CodeFactoryException($"Could not create the source code for a contract event handler.");
                    }

                    if (currentClass.Methods.Any(m => m.Name == eventHandlerName))
                    {
                        continue;
                    }

                    var eventHandlerSource = CSharpSourceGenerationWPF.GenerateContractEventHandlerMethod(subscriptionField, contractEvent,
                                                                                                          namespaceManager);

                    if (eventHandlerSource == null)
                    {
                        throw new CodeFactoryException($"Could not create the source code for the event handler {eventHandlerName}");
                    }

                    sourceCode = await currentClass.AddToEndAsync(subscribePath.filePath, InjectSourceCodeAtLevel(2, eventHandlerSource));

                    currentClass = sourceCode.GetModel(currentClass.LookupPath) as CsClass;
                    if (currentClass == null)
                    {
                        throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription");
                    }
                }

                var subscriptionName   = CSharpSourceGenerationWPF.GenerateContractSubscriptionMethodName(subscriptionField);
                var subscriptionMethod = currentClass.Methods.FirstOrDefault(m => m.Name == subscriptionName);

                if (subscriptionMethod != null)
                {
                    sourceCode = await subscriptionMethod.DeleteAsync();

                    currentClass = sourceCode.GetModel(currentClass.LookupPath) as CsClass;
                    if (currentClass == null)
                    {
                        throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription");
                    }
                }

                var subscriptionSource = CSharpSourceGenerationWPF.GenerateContractSubscriptionMethod(subscriptionField, contract);

                if (subscriptionSource == null)
                {
                    throw new CodeFactoryException("Cannot generate the subscription contract source code.");
                }

                sourceCode = await currentClass.AddToEndAsync(subscribePath.filePath, InjectSourceCodeAtLevel(2, subscriptionSource));

                currentClass = sourceCode.GetModel(currentClass.LookupPath) as CsClass;
                if (currentClass == null)
                {
                    throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription");
                }

                var releaseName   = CSharpSourceGenerationWPF.GenerateContractReleaseMethodName(subscriptionField);
                var releaseMethod = currentClass.Methods.FirstOrDefault(m => m.Name == releaseName);

                if (releaseMethod != null)
                {
                    sourceCode = await releaseMethod.DeleteAsync();

                    currentClass = sourceCode.GetModel(currentClass.LookupPath) as CsClass;
                    if (currentClass == null)
                    {
                        throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription");
                    }
                }

                var releaseSource = CSharpSourceGenerationWPF.GenerateContractReleaseMethod(subscriptionField, contract);

                if (releaseSource == null)
                {
                    throw new CodeFactoryException("Cannot generate the release contract source code.");
                }

                sourceCode = await currentClass.AddToEndAsync(subscribePath.filePath, InjectSourceCodeAtLevel(2, releaseSource));
            }
            catch (CodeFactoryException)
            {
                throw;
            }
            catch (Exception unhandledException)
            {
                throw new CodeFactoryException("The following unhandledException occured", unhandledException);
            }

            return(sourceCode);
        }
        /// <summary>
        /// Loads the parent of the source code document.
        /// </summary>
        /// <param name="source">Target source code.</param>
        /// <param name="noDocument">Flag that will determine if the parent is a document to keep searching for parent.</param>
        /// <returns>The parent model.</returns>
        public static async Task <VsModel> GetParentAsync(this VsCSharpSource source, bool noDocument = true)
        {
            if (source == null)
            {
                return(null);
            }
            if (!source.IsLoaded)
            {
                return(null);
            }
            var document = await source.LoadDocumentModelAsync();

            VsCSharpSource sourceDocument = null;
            VsModel        parent         = null;

            if (!noDocument)
            {
                return(await document.GetParentAsync());
            }

            bool found = false;

            while (!found)
            {
                if (sourceDocument != null)
                {
                    parent = await sourceDocument.GetParentAsync(true);
                }
                else
                {
                    parent = await document.GetParentAsync();
                }

                if (parent == null)
                {
                    break;
                }

                switch (parent.ModelType)
                {
                case VisualStudioModelType.Solution:
                    found = true;
                    break;

                case VisualStudioModelType.SolutionFolder:
                    found = true;
                    break;

                case VisualStudioModelType.Project:
                    found = true;
                    break;

                case VisualStudioModelType.ProjectFolder:
                    found = true;
                    break;

                case VisualStudioModelType.Document:

                    document = parent as VsDocument;
                    if (document == null)
                    {
                        throw new CodeFactoryException("Cannot load the document information, cannot get the parent model.");
                    }
                    sourceDocument = null;

                    break;

                case VisualStudioModelType.CSharpSource:

                    sourceDocument = parent as VsCSharpSource;
                    if (sourceDocument == null)
                    {
                        throw new CodeFactoryException("Cannot load the document information, cannot get the parent model.");
                    }
                    document = null;
                    break;

                default:
                    found = false;
                    break;
                }
            }

            return(parent);
        }
        /// <summary>
        /// Gets the parent for the current C# source code model.
        /// </summary>
        /// <param name="source">Source model to load.</param>
        /// <returns>Tuple containing the location and target model. If the model is null then the parent is outside of a project implementation, or could not be loaded.</returns>
        public static async Task <(bool IsProject, VsModel ParentModel)> GetCSharpSourceDocumentParentAsync(this VsCSharpSource source)
        {
            if (source == null)
            {
                return(false, null);
            }

            var parent = await source.GetParentAsync();

            if (parent.ModelType == VisualStudioModelType.Project)
            {
                return(true, parent);
            }

            return(parent.ModelType == VisualStudioModelType.ProjectFolder ? (false, parent) : (false, null));
        }
Exemplo n.º 14
0
        /// <summary>
        /// Code factory framework calls this method when the command has been executed.
        /// </summary>
        /// <param name="result">The code factory model that has generated and provided to the command to process.</param>
        public override async Task ExecuteCommandAsync(VsCSharpSource result)
        {
            try
            {
                var references = await result.GetHostProjectReferencesAsync();

                if (!references.Any())
                {
                    return;
                }

                bool hasLogging   = references.Any(r => r.Name == NetConstants.MicrosoftExtensionsLoggingLibraryName);
                bool hasCDF       = references.Any(r => r.Name == CommonDeliveryFrameworkConstants.CommonDeliveryFrameworkAssemblyName);
                bool hasCDFAspnet = references.Any(r =>
                                                   r.Name == CommonDeliveryFrameworkConstants.CommonDeliveryFrameworkNetAspNetAssemblyName);

                var sourceCode = result.SourceCode;


                foreach (var sourceCodeClass in sourceCode.Classes)
                {
                    var missingMembers = sourceCodeClass.MissingInterfaceMembers();

                    if (missingMembers == null)
                    {
                        continue;
                    }
                    if (!missingMembers.Any())
                    {
                        continue;
                    }

                    IEnumerable <CsMember> baseMembers = null;

                    var updatedClass = sourceCodeClass;

                    var contractMembers = ContractHelper.MissingContractMembers(sourceCodeClass, missingMembers);

                    baseMembers = contractMembers != null?ContractHelper.MissingBaseMembers(missingMembers, contractMembers) : missingMembers;

                    if (contractMembers != null)
                    {
                        sourceCode = await ContractHelper.GetContractSourceFileAsync(result, sourceCodeClass);

                        if (sourceCode == null)
                        {
                            throw new CodeFactoryException("Cannot load the source code for the contract to support this class.");
                        }

                        updatedClass = sourceCode.GetModel(updatedClass.LookupPath) as CsClass;
                        if (updatedClass == null)
                        {
                            throw new CodeFactoryException("Cannot get class data to add members.");
                        }

                        sourceCode = await UpdateFileAsync(updatedClass, sourceCode, contractMembers,
                                                           hasLogging, hasCDF, hasCDFAspnet, true);

                        if (baseMembers != null)
                        {
                            sourceCode = await ContractHelper.GetContractBaseFileAsync(result, sourceCodeClass);
                        }

                        if (sourceCode == null)
                        {
                            throw new CodeFactoryException("Cannot load the source code for the class.");
                        }

                        updatedClass = sourceCode.GetModel(updatedClass.LookupPath) as CsClass;
                        if (updatedClass == null)
                        {
                            throw new CodeFactoryException("Cannot get class data to add members.");
                        }
                    }

                    if (baseMembers != null)
                    {
                        sourceCode = await UpdateFileAsync(updatedClass, sourceCode, baseMembers,
                                                           hasLogging, hasCDF, hasCDFAspnet, false);
                    }
                }
            }
            catch (Exception unhandledError)
            {
                _logger.Error($"The following unhandled error occured while executing the solution explorer C# document command {commandTitle}. ",
                              unhandledError);
            }
        }
        /// <summary>
        /// Helper method that converts Aspx Pages to Blazor pages.
        /// </summary>
        /// <param name="sourcePage">The source aspx page to be converted.</param>
        /// <param name="targetProject">The target blazor project to write to.</param>
        /// <param name="targetPagesFolder">The target visual studio project folder the converted aspx will be added to.</param>
        /// <param name="sourceCodeBehind">Optional parameter that provides the code behind file for the aspx page to be converted also.</param>
        /// <returns>Flag used to determine if the conversion was successful.</returns>
        private async Task ConvertAspxPage(VsDocument sourcePage, VsProject targetProject, VsProjectFolder targetPagesFolder, VsCSharpSource sourceCodeBehind = null, VsDocument sourceDocCodeBehind = null)
        {
            try
            {
                //Getting the content from the source document.
                var pageContent = await sourcePage.GetDocumentContentAsStringAsync(); //File.ReadAllText(result.Path);

                //grab the <%Page element from the source and pull it from the text.  Its meta data anyway and just screws up the conversion down the line.
                var pageHeaderData = System.Text.RegularExpressions.Regex.Match(pageContent, @"<%@\s*[^%>]*(.*?)\s*%>").Value;

                if (pageHeaderData.Length > 0)
                {
                    pageContent = Regex.Replace(pageContent, @"<%@\s*[^%>]*(.*?)\s*%>", string.Empty);
                }

                //Swap ASP.NET string tokens for Razor syntax  (<%, <%@, <%:, <%#:, etc
                var targetText = RemoveASPNETSyntax(pageContent);

                //Convert ASP.NET into Razor syntax.  **This actually presumes that any controls like <asp:ListView..
                //will have an equivalent Razor component in place called <ListView.. etc
                var conversionData = await ReplaceAspControls(targetText);

                //Drop the pageHeaderData into the Dictionary for later processing by any downstream T4 factories
                conversionData.Add("HeaderData", pageHeaderData);

                //Getting the source code from the code behind file provided.
                var codeSource = sourceCodeBehind?.SourceCode;
                if ((codeSource == null) && (sourceDocCodeBehind != null))
                {
                    codeSource = await sourceDocCodeBehind.GetCSharpSourceModelAsync();
                }

                //put the files in the target project
                String targetFileName = Path.GetFileNameWithoutExtension(sourcePage.Path);
                conversionData.Add("Namespace", $"{targetProject.DefaultNamespace}.Pages");

                //Setup Page directives, using statements etc
                var targetWithMeta = await SetRazorPageDirectives(targetFileName, conversionData);

                //Adding the converted content from the aspx page to the new razor page.
                VsDocument success = await targetPagesFolder.AddDocumentAsync($"{targetFileName}.razor", targetWithMeta);

                if (success != null)
                {
                    //Updating the dialog with the status the aspx page has been converted.
                    await _statusTracking.UpdateCurrentStatusAsync(MigrationStepEnum.AspxPages,
                                                                   MessageTypeEnum.Information,
                                                                   $"Converted the aspx page to a razor page, added razor page {targetFileName}.razor");

                    //If we have the source code from the original aspx page add it to the razor pages folder.
                    if (codeSource != null)
                    {
                        //Creating a CodeFactory model store this will be used to pass data to a T4 factory.
                        CsModelStore modelStore = new CsModelStore();

                        //Adding the current class from the code behind into the model store for processing.
                        modelStore.SetModel(codeSource.Classes.FirstOrDefault());

                        //Processing the T4 factory and loading the source code.
                        var codeBehindFormattedSourceCode =
                            Templates.PageCodeBehind.GenerateSource(modelStore, conversionData);

                        //Calling the CodeFactory project system and adding a new code behind file and injecting the formatted code into the file.
                        var codeBehind = await targetPagesFolder.AddDocumentAsync($"{targetFileName}.razor.cs", codeBehindFormattedSourceCode);

                        if (codeBehind != null)
                        {
                            //Updating the dialog with the status the aspx page code behind has been converted.
                            await _statusTracking.UpdateCurrentStatusAsync(MigrationStepEnum.AspxPages,
                                                                           MessageTypeEnum.Information,
                                                                           $"Converted the aspx page code behind file to a razor page code behind file, added code behind file {targetFileName}.razor.cs");
                        }
                        else
                        {
                            //Updating the dialog with the status the aspx page code behind failed
                            await _statusTracking.UpdateCurrentStatusAsync(MigrationStepEnum.AspxPages,
                                                                           MessageTypeEnum.Error,
                                                                           $"Failed the conversion of the aspx page code behind file to a razor page code behind file {targetFileName}.razor.cs");
                        }
                    }
                }
                else
                {
                    //Updating the dialog with the status the aspx page failed conversion.
                    await _statusTracking.UpdateCurrentStatusAsync(MigrationStepEnum.AspxPages,
                                                                   MessageTypeEnum.Error,
                                                                   $"Failed the conversion of the aspx page {targetFileName}.razor. Will not convert the code behind file.");
                }
            }
            catch (Exception unhandledError)
            {
                await _statusTracking.UpdateCurrentStatusAsync(MigrationStepEnum.AspxPages, MessageTypeEnum.Error,
                                                               $"The following unhandled error occured while trying to convert the aspx page. '{unhandledError.Message}'");
            }
        }
        /// <summary>
        /// Will get the list of project references for the project that hosts this source code.
        /// </summary>
        /// <param name="source">The source code to get the references from.</param>
        /// <returns>The references or an empty list.</returns>
        public static async Task <IReadOnlyList <VsReference> > GetHostProjectReferencesAsync(this VsCSharpSource source)
        {
            IReadOnlyList <VsReference> result = ImmutableList <VsReference> .Empty;

            if (source == null)
            {
                return(result);
            }

            if (!source.IsLoaded)
            {
                return(result);
            }

            var project = await source.GetHostingProjectAsync();

            if (project == null)
            {
                return(result);
            }

            result = await project.GetProjectReferencesAsync();

            return(result);
        }
        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);
            }
        }