/// <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); }
/// <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); }
/// <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)); }
/// <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); }
/// <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); } }
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)); }
/// <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); } }