/// <summary> /// This method is used to send an Element through any registered ControlConverter adapters and get back /// the migrated text from the AdapterHost. /// </summary> /// <param name="elementToProcess"></param> /// <returns>String</returns> private async Task <string> ProcessSourceElement(string elementToProcess, AdapterHost host) { HtmlNode processedElement = null; StringBuilder processedHTML = new StringBuilder(); var htmlParser = new HtmlDocument(); htmlParser.LoadHtml(elementToProcess); var contentControlObj = htmlParser.DocumentNode.FirstChild; try { //If this is an ASP:* control then call the migration code, append the *entire* migrated node, and return to the calling method. if (contentControlObj.Name.ToLower().Contains("asp:")) { var newNodeText = await host.ConvertTag(contentControlObj.Name, contentControlObj.OuterHtml); //We do *not* deal with any children of this element, as that is the responsibility of the MigratTagControl to deal with any children of the ASP control return(newNodeText); } else { //if the current element has children, // - add it to the targetDocumentFragment without the children attached // - recursively call this method to deal with the children, passing in the new appended as the parent element to append children too if (contentControlObj.ChildNodes.Count > 0) { //shallow clone processedElement = contentControlObj.CloneNode(false); foreach (var item in contentControlObj.ChildNodes) { if (item.NodeType == HtmlNodeType.Element) { var migratedValue = await ProcessSourceElement(item.OuterHtml, host); var migratedChild = HtmlNode.CreateNode(migratedValue.Length > 0 ? migratedValue : " "); processedElement.AppendChild(migratedChild); } } processedHTML.Append(processedElement.OuterHtml); } else { processedHTML.Append((contentControlObj.Clone()).OuterHtml); } return(processedHTML.ToString()); } } catch (Exception ex) { throw ex; } finally { htmlParser = null; } }
/// <summary> /// This method is used to convert the asp:Content control to a Blazor equivalent. In this particular /// case - there is no equivalent. This control is the top-level asp:* container for a page and really just holds all other /// controls that are found in an *.aspx page definition. /// </summary> /// <param name="nodeContent"></param> /// <returns></returns> private async Task <string> ConvertContentControl(string nodeContent) { string _result = string.Empty; var model = new HtmlDocument(); var innerModel = new HtmlDocument(); HtmlNode returnNode; try { model.LoadHtml(nodeContent); var contentControlObj = model.DocumentNode.FirstChild; returnNode = contentControlObj.CloneNode(false); innerModel.LoadHtml(contentControlObj.InnerHtml); //<-- this is where we actually remove the asp:content control from the model //send any child asp:* controls to be converted by the a call back out to the adapterHosting class. var allchildren = innerModel.DocumentNode.Descendants().Where(p => p.Name.ToLower().Contains("asp:")); List <HtmlNode> targetedChildren = new List <HtmlNode>(); //filter out nested asp:* controls from the list (children are processed by the specific adapter converter method) //this way we don't end up double-calling a AdapterHost.ConvertTag on controls that have already been taken care of by their //parent asp:* control converter foreach (var control in allchildren) { var anc1 = control.Ancestors().Where(c => c.Name.Contains("asp:")); if (!anc1.Any()) { targetedChildren.Add(control); } } foreach (var nodeObj in targetedChildren) { var migratedControlText = await AdapterHost.ConvertTag(nodeObj.Name, nodeObj.OuterHtml); var tempNode = HtmlNode.CreateNode(migratedControlText); nodeObj.ParentNode.ReplaceChild(tempNode, nodeObj); } return(innerModel.DocumentNode.OuterHtml); } catch (Exception ex) { throw ex; } finally { model = null; } }
/// <summary> /// This method understands now to convert an asp:FormView control into a blazor equivalent. /// </summary> /// <param name="nodeContent"></param> /// <returns></returns> private async Task <string> ConvertListViewControl(string nodeContent) { //var model = await _angleSharpContext.OpenAsync(req => req.Content(nodeContent)); var currentModel = new HtmlDocument(); var newModel = new HtmlDocument(); currentModel.LoadHtml(nodeContent); try { var listViewNode = currentModel.DocumentNode.FirstChild;// ("//asp:listview");// model.All.Where(p => p.LocalName.ToLower().Equals("asp:formview")).FirstOrDefault(); newModel.LoadHtml($"<ListView Model={listViewNode.GetAttributeValue("ItemType", "")} OnValidSubmit={listViewNode.GetAttributeValue("SelectMethod", "")}></ListView>"); var newNode = newModel.DocumentNode.SelectSingleNode("//listview"); //this is now a live list having substituted the EditForm control for the old FormView one newNode.AppendChildren(listViewNode.ChildNodes); //send any child asp:* controls to be converted by the a call back out to the adapterHosting class. var aspFormTags = newModel.DocumentNode.FirstChild.Descendants().Where(p => p.Name.ToLower().Contains("asp:")).ToList(); foreach (var formObj in aspFormTags) { var migratedControlText = await AdapterHost.ConvertTag(formObj.Name, formObj.OuterHtml); var tempNode = HtmlNode.CreateNode(migratedControlText); formObj.ParentNode.ReplaceChild(tempNode, formObj); } return(newModel.DocumentNode.OuterHtml); } catch (Exception ex) { throw ex; } finally { currentModel = null; newModel = null; } }
/// <summary> /// This method understands now to convert an asp:FormView control into a blazor equivalent. /// </summary> /// <param name="nodeContent"></param> /// <returns></returns> private async Task <string> ConvertFormViewControl(string nodeContent) { var currentModel = new HtmlDocument(); var newModel = new HtmlDocument(); currentModel.LoadHtml(nodeContent); try { var editFormNode = currentModel.DocumentNode.FirstChild;// ("//asp:listview");// model.All.Where(p => p.LocalName.ToLower().Equals("asp:formview")).FirstOrDefault(); newModel.LoadHtml($"<EditForm Model={editFormNode.GetAttributeValue("ItemType", "")} OnValidSubmit={editFormNode.GetAttributeValue("SelectMethod", "")}></EditForm>"); var newNode = newModel.DocumentNode.SelectSingleNode("//editform"); //this is now a live list having substituted the EditForm control for the old FormView one newNode.AppendChildren(editFormNode.ChildNodes); //deal with itemtemplates... ?? //send any child asp:* controls to be converted by the a call back out to the adapterHosting class. var aspFormTags = newModel.DocumentNode.FirstChild.Descendants().Where(p => p.Name.ToLower().Contains("asp:")).ToList(); foreach (var formObj in aspFormTags) { var migratedControlText = await AdapterHost.ConvertTag(formObj.Name, formObj.OuterHtml); var tempNode = HtmlNode.CreateNode(migratedControlText); formObj.ParentNode.ReplaceChild(tempNode, formObj); } return(newModel.DocumentNode.OuterHtml); //var editFormNode = model.All.Where(p => p.LocalName.ToLower().Equals("asp:formview")).FirstOrDefault(); //var newNode = parser.ParseFragment($"<EditForm Model={editFormNode.GetAttribute("ItemType")} OnValidSubmit={editFormNode.GetAttribute("SelectMethod")}></EditForm>", editFormNode); ////this is now a live list having substituted the EditForm control for the old FormView one //newNode.First().AppendNodes(editFormNode.ChildNodes.ToArray()); //if (model.All.Any(p => p.TagName.ToLower().Equals("itemtemplate"))) //{ // //deal with itemtemplates... ?? //} ////send any child asp:* controls to be converted by the a call back out to the adapterHosting class. //var aspFormTags = newNode.First().Descendents<IElement>().Where(p => p.NodeName.ToLower().Contains("asp:")).ToList(); //foreach (var formObj in aspFormTags) //{ // var migratedControlText = await _adapterHost.MigrateTagControl(formObj.NodeName, formObj.OuterHtml); // var tempNode = parser.ParseFragment(migratedControlText, null); // //ParseFragment always adds on a HTML & BODY tags, at least with this call setup. We need to pull out *just* the element that we have migrated. // var appendElement = tempNode.GetElementsByTagName("BODY").First().ChildNodes; // formObj.Replace(appendElement.ToArray()); //} //return newNode.First().ToHtml();//.OuterHTML; // .ToString(); } catch (Exception ex) { throw ex; } finally { currentModel = null; newModel = null; } }
/// <summary> /// This method is used to generically convert an asp control by removing the 'asp:' /// prefix from the control name and then returning the resultant content back to the caller. /// </summary> /// <param name="nodeContent"></param> /// <returns>converted control content</returns> private async Task <string> ConvertGenericControl(string nodeContent) { var model = new HtmlDocument(); model.LoadHtml(nodeContent); HtmlNode rootNode = null; try { rootNode = model.DocumentNode.FirstChild; if (rootNode.Name.Contains("asp:")) { rootNode.Name = rootNode.Name.Replace("asp:", string.Empty); } //send any child asp:* controls to be converted by the a call back out to the adapterHosting class. var allchildren = rootNode.Descendants().Where(p => p.Name.ToLower().Contains("asp:")); List <HtmlNode> targetedChildren = new List <HtmlNode>(); //filter out nested asp:* controls from the list (children are processed by the specific adapter converter method) //this way we don't end up double-calling a AdapterHost.ConvertTag on controls that have already been taken care of by their //parent asp:* control converter foreach (var control in allchildren) { var anc1 = control.Ancestors().Where(c => c.Name.Contains("asp:")); if (!anc1.Any()) { targetedChildren.Add(control); } } foreach (var nodeObj in targetedChildren) { var migratedControlText = await AdapterHost.ConvertTag(nodeObj.Name, nodeObj.OuterHtml); var tempNode = HtmlNode.CreateNode(migratedControlText); nodeObj.ParentNode.ReplaceChild(tempNode, nodeObj); } //var aspFormTags = rootNode.Descendants().Where(p => p.Name.ToLower().Contains("asp:"));//.ToList(); //foreach (var control in aspFormTags) //{ // var migratedControlText = await AdapterHost.ConvertTag(control.Name, control.OuterHtml); // var tempNode = HtmlNode.CreateNode(migratedControlText); // control.ParentNode.ReplaceChild(tempNode, control); //} return(rootNode.OuterHtml); } catch (Exception ex) { throw ex; } finally { model = null; } }
private async Task <Dictionary <string, string> > ReplaceAspControls(string sourceAspCode) { Dictionary <string, string> result = new Dictionary <string, string>(); StringBuilder migratedSource = new StringBuilder(); var docFrag = new HtmlAgilityPack.HtmlDocument(); docFrag.LoadHtml(sourceAspCode); var converterAdapterHost = new AdapterHost(); converterAdapterHost.RegisterAdapter(x => new AspxToBlazorControlConverter(converterAdapterHost)); try { //Deal with HTML, HEAD and BODY tags (most *.aspx pages won't have these - but we still have to manage those that do) //Look through the incoming sourceAspCode parameter and see if we have any of those three tags present. var htmlTag = System.Text.RegularExpressions.Regex.Match(sourceAspCode, @"<HTML.*?>(.|\n)*?<\/HTML>", RegexOptions.IgnoreCase); var headTag = System.Text.RegularExpressions.Regex.Match(sourceAspCode, @"<HEAD.*?>(.|\n)*?<\/HEAD>", RegexOptions.IgnoreCase); var bodyTag = System.Text.RegularExpressions.Regex.Match(sourceAspCode, @"<BODY>(.|\n)*?<\/BODY>", RegexOptions.IgnoreCase); foreach (var child in docFrag.DocumentNode.ChildNodes) { //New HtmlAgilityPack parsing which does *not* add HTML/HEAD/BODY etc tags to the source if (child.Name.ToLower().Equals("html")) { //migratedSource.Append(await ProcessSourceElement(child.OuterHtml, converterAdapterHost)); continue; } if (child.Name.ToLower().Equals("head")) { //just take the value of the headTag Regex match from earlier in this method (there are no asp:* controls of any kind that live in the //HEAD tag - so we can just copy it down to here) migratedSource.Append(await ProcessSourceElement(child.OuterHtml, converterAdapterHost)); continue; } if (child.Name.ToLower().Equals("body")) { //We go ahead and process this element. Any children of the tag are actually handled by the ProcessSourceElement() method var migratedBodyElement = await ProcessSourceElement(child.OuterHtml, converterAdapterHost); if (!bodyTag.Success) { var matches = Regex.Match(migratedBodyElement, @"<body>([\S\s]*)<\/body>", RegexOptions.IgnoreCase); migratedSource.Append(matches.Groups[1].Value); } else { migratedSource.Append(migratedBodyElement); } continue; } //Its just a vanilla text sitting outside of a elementNode, append it. if (!child.NodeType.Equals(HtmlNodeType.Element)) { migratedSource.Append(child.OuterHtml); continue; } //Its an element Node - process it. if (child.NodeType.Equals(HtmlNodeType.Element)) { migratedSource.Append(await ProcessSourceElement(child.OuterHtml, converterAdapterHost)); continue; } } result.Add("source", sourceAspCode); result.Add("alteredSource", migratedSource.ToString()); } catch (Exception ex) { throw; } return(result); }