Skip to content

Commit cae1b2d

Browse files
committed
Removed AngleSharp and replaced the HTML parser utility with the HTMLAgility Pack. Updated control converter code to be more simple and more robust.
1 parent f1761f3 commit cae1b2d

File tree

5 files changed

+171
-102
lines changed

5 files changed

+171
-102
lines changed

src/WebFormsToBlazorServerCommands/Migration/AspxToBlazorControlConverter.cs renamed to src/WebFormsToBlazorServerCommands/Migration/Adapters/AspxToBlazorControlConverter.cs

Lines changed: 106 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,9 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq;
4-
using System.Net.NetworkInformation;
5-
using System.ServiceModel.Configuration;
6-
using System.Text;
7-
using System.Text.RegularExpressions;
84
using System.Threading.Tasks;
9-
using AngleSharp;
10-
using AngleSharp.Dom;
11-
using AngleSharp.Html.Parser;
125
using CodeFactory.Formatting.CSharp;
13-
using NLog.Targets.Wrappers;
6+
using HtmlAgilityPack;
147

158
namespace WebFormsToBlazorServerCommands.Migration
169
{
@@ -19,8 +12,6 @@ namespace WebFormsToBlazorServerCommands.Migration
1912
/// </summary>
2013
public class AspxToBlazorControlConverter : ControlConverterBase
2114
{
22-
private static AngleSharp.IConfiguration _angleSharpConfig = AngleSharp.Configuration.Default;
23-
private static AngleSharp.IBrowsingContext _angleSharpContext = null;
2415

2516
public AspxToBlazorControlConverter(ITagControlConverter adapterHost) : base(adapterHost)
2617
{
@@ -50,7 +41,6 @@ public AspxToBlazorControlConverter(ITagControlConverter adapterHost) : base(ada
5041
_TagsICanConvert.Add("asp:datagrid");
5142
_TagsICanConvert.Add("asp:dropdownlist");
5243

53-
_angleSharpContext = BrowsingContext.New(_angleSharpConfig);
5444
}
5545

5646
/// <summary>
@@ -77,6 +67,10 @@ public override async Task<string> ConvertControlTag(string tagName, string tagN
7767
_result = await ConvertEditFormControl(tagNodeContent);
7868
break;
7969

70+
case "asp:listview":
71+
_result = await ConvertListViewControl(tagNodeContent);
72+
break;
73+
8074
default:
8175
_result = await ConvertGenericControl(tagNodeContent);
8276
break;
@@ -96,6 +90,8 @@ public override async Task<string> ConvertControlTag(string tagName, string tagN
9690
/// <returns>converted control content</returns>
9791
private async Task<string> ConvertGenericControl(string nodeContent)
9892
{
93+
var model = new HtmlDocument();
94+
model.LoadHtml(nodeContent);
9995

10096
try
10197
{
@@ -105,7 +101,17 @@ private async Task<string> ConvertGenericControl(string nodeContent)
105101
return nodeContent;
106102
}
107103

108-
return nodeContent.Substring(0, pos) + "" + nodeContent.Substring(pos + "asp:".Length);
104+
//send any child asp:* controls to be converted by the a call back out to the adapterHosting class.
105+
var aspFormTags = model.DocumentNode.Descendants().Where(p => p.Name.ToLower().Contains("asp:")).ToList();
106+
foreach (var formObj in aspFormTags)
107+
{
108+
var migratedControlText = await _adapterHost.MigrateTagControl(formObj.Name, formObj.OuterHtml);
109+
var tempNode = HtmlNode.CreateNode(migratedControlText);
110+
111+
formObj.ParentNode.ReplaceChild(tempNode, formObj);
112+
}
113+
114+
return model.DocumentNode.OuterHtml;
109115
}
110116
catch (Exception ex)
111117
{
@@ -121,36 +127,99 @@ private async Task<string> ConvertGenericControl(string nodeContent)
121127
/// <returns></returns>
122128
private async Task<string> ConvertFormViewControl(string nodeContent)
123129
{
124-
var model = await _angleSharpContext.OpenAsync(req => req.Content(nodeContent));
125-
var parser = new HtmlParser();
130+
var currentModel = new HtmlDocument();
131+
var newModel = new HtmlDocument();
132+
currentModel.LoadHtml(nodeContent);
126133

127134
try
128135
{
129-
var editFormNode = model.All.Where(p => p.LocalName.ToLower().Equals("asp:formview")).FirstOrDefault();
130-
var newNode = parser.ParseFragment($"<EditForm Model={editFormNode.GetAttribute("ItemType")} OnValidSubmit={editFormNode.GetAttribute("SelectMethod")}></EditForm>", editFormNode);
136+
var editFormNode = currentModel.DocumentNode.FirstChild;// ("//asp:listview");// model.All.Where(p => p.LocalName.ToLower().Equals("asp:formview")).FirstOrDefault();
131137

138+
newModel.LoadHtml($"<EditForm Model={editFormNode.GetAttributeValue("ItemType", "")} OnValidSubmit={editFormNode.GetAttributeValue("SelectMethod","")}></EditForm>");
139+
var newNode = newModel.DocumentNode.SelectSingleNode("//editform");
132140
//this is now a live list having substituted the EditForm control for the old FormView one
133-
newNode.First().AppendNodes(editFormNode.ChildNodes.ToArray());
141+
newNode.AppendChildren(editFormNode.ChildNodes);
142+
143+
//deal with itemtemplates... ??
134144

135-
if (model.All.Any(p => p.TagName.ToLower().Equals("itemtemplate")))
145+
//send any child asp:* controls to be converted by the a call back out to the adapterHosting class.
146+
var aspFormTags = newModel.DocumentNode.FirstChild.Descendants().Where(p => p.Name.ToLower().Contains("asp:")).ToList();
147+
foreach (var formObj in aspFormTags)
136148
{
137-
//deal with itemtemplates... ??
149+
var migratedControlText = await _adapterHost.MigrateTagControl(formObj.Name, formObj.OuterHtml);
150+
var tempNode = HtmlNode.CreateNode(migratedControlText);
151+
152+
formObj.ParentNode.ReplaceChild(tempNode, formObj);
138153
}
139154

155+
return newModel.DocumentNode.OuterHtml;
156+
157+
//var editFormNode = model.All.Where(p => p.LocalName.ToLower().Equals("asp:formview")).FirstOrDefault();
158+
//var newNode = parser.ParseFragment($"<EditForm Model={editFormNode.GetAttribute("ItemType")} OnValidSubmit={editFormNode.GetAttribute("SelectMethod")}></EditForm>", editFormNode);
159+
160+
////this is now a live list having substituted the EditForm control for the old FormView one
161+
//newNode.First().AppendNodes(editFormNode.ChildNodes.ToArray());
162+
163+
//if (model.All.Any(p => p.TagName.ToLower().Equals("itemtemplate")))
164+
//{
165+
// //deal with itemtemplates... ??
166+
//}
167+
168+
////send any child asp:* controls to be converted by the a call back out to the adapterHosting class.
169+
//var aspFormTags = newNode.First().Descendents<IElement>().Where(p => p.NodeName.ToLower().Contains("asp:")).ToList();
170+
//foreach (var formObj in aspFormTags)
171+
//{
172+
// var migratedControlText = await _adapterHost.MigrateTagControl(formObj.NodeName, formObj.OuterHtml);
173+
// var tempNode = parser.ParseFragment(migratedControlText, null);
174+
175+
// //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.
176+
// var appendElement = tempNode.GetElementsByTagName("BODY").First().ChildNodes;
177+
178+
// formObj.Replace(appendElement.ToArray());
179+
//}
180+
181+
//return newNode.First().ToHtml();//.OuterHTML; // .ToString();
182+
}
183+
catch (Exception ex)
184+
{
185+
186+
throw ex;
187+
}
188+
}
189+
190+
/// <summary>
191+
/// This method understands now to convert an asp:FormView control into a blazor equivalent.
192+
/// </summary>
193+
/// <param name="nodeContent"></param>
194+
/// <returns></returns>
195+
private async Task<string> ConvertListViewControl(string nodeContent)
196+
{
197+
//var model = await _angleSharpContext.OpenAsync(req => req.Content(nodeContent));
198+
var currentModel = new HtmlDocument();
199+
var newModel = new HtmlDocument();
200+
currentModel.LoadHtml(nodeContent);
201+
202+
203+
try
204+
{
205+
var listViewNode = currentModel.DocumentNode.FirstChild;// ("//asp:listview");// model.All.Where(p => p.LocalName.ToLower().Equals("asp:formview")).FirstOrDefault();
206+
207+
newModel.LoadHtml($"<ListView Model={listViewNode.GetAttributeValue("ItemType","")} OnValidSubmit={listViewNode.GetAttributeValue("SelectMethod","")}></ListView>");
208+
var newNode = newModel.DocumentNode.SelectSingleNode("//listview");
209+
//this is now a live list having substituted the EditForm control for the old FormView one
210+
newNode.AppendChildren(listViewNode.ChildNodes);
211+
140212
//send any child asp:* controls to be converted by the a call back out to the adapterHosting class.
141-
var aspFormTags = newNode.First().Descendents<IElement>().Where(p => p.NodeName.ToLower().Contains("asp:")).ToList();
213+
var aspFormTags = newModel.DocumentNode.FirstChild.Descendants().Where(p => p.Name.ToLower().Contains("asp:")).ToList();
142214
foreach (var formObj in aspFormTags)
143215
{
144-
var migratedControlText = await _adapterHost.MigrateTagControl(formObj.NodeName, formObj.OuterHtml);
145-
var tempNode = parser.ParseFragment(migratedControlText, null);
146-
147-
//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.
148-
var appendElement = tempNode.GetElementsByTagName("BODY").First().ChildNodes;
216+
var migratedControlText = await _adapterHost.MigrateTagControl(formObj.Name, formObj.OuterHtml);
217+
var tempNode = HtmlNode.CreateNode(migratedControlText);
149218

150-
formObj.Replace(appendElement.ToArray());
219+
formObj.ParentNode.ReplaceChild(tempNode, formObj);
151220
}
152221

153-
return newNode.First().ToHtml();//.OuterHTML; // .ToString();
222+
return newModel.DocumentNode.OuterHtml;
154223
}
155224
catch (Exception ex)
156225
{
@@ -190,30 +259,26 @@ private async Task<string> ConvertEditFormControl(string nodeContent)
190259
private async Task<string> ConvertContentControl(string nodeContent)
191260
{
192261
string _result = string.Empty;
193-
var parser = new HtmlParser();
262+
var model = new HtmlDocument();
194263

195264
try
196265
{
197-
var model = await _angleSharpContext.OpenAsync(req => req.Content(nodeContent));
198-
var contentControlObj = model.Descendents<Element>().First(c => c.TagName.ToLower().Equals("asp:content"));
266+
model.LoadHtml(nodeContent);
267+
var contentControlObj = model.DocumentNode.FirstChild;
199268

200269
//send any child asp:* controls to be converted by the a call back out to the adapterHosting class.
201-
var aspFormTags = contentControlObj.Descendents<IElement>().Where(p => p.NodeName.ToLower().Contains("asp:")).ToList();
270+
var aspFormTags = contentControlObj.Descendants().Where(p => p.Name.ToLower().Contains("asp:")).ToList();
202271
foreach (var formObj in aspFormTags)
203272
{
204-
var migratedControlText = await _adapterHost.MigrateTagControl(formObj.NodeName, formObj.OuterHtml);
205-
var tempNode = parser.ParseFragment(migratedControlText, null);
273+
var migratedControlText = await _adapterHost.MigrateTagControl(formObj.Name, formObj.OuterHtml);
274+
var tempNode = HtmlNode.CreateNode(migratedControlText);
206275

207-
//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.
208-
var appendElement = tempNode.GetElementsByTagName("BODY").First().ChildNodes;
209-
210-
formObj.Replace(appendElement.ToArray());
276+
formObj.ParentNode.ReplaceChild(tempNode, formObj);
211277
}
212278

213-
//There isn't any asp:content control equivalent in Blazor, so we'll just take the innerHTML
214-
_result = contentControlObj.InnerHtml;
215-
216-
return _result;
279+
//There isn't any asp:content control equivalent, so we'll just return the innerHTML
280+
return contentControlObj.InnerHtml;
281+
217282
}
218283
catch (Exception ex)
219284
{

src/WebFormsToBlazorServerCommands/Migration/ControlConverterBase.cs renamed to src/WebFormsToBlazorServerCommands/Migration/Adapters/ControlConverterBase.cs

File renamed without changes.

src/WebFormsToBlazorServerCommands/Migration/WebFormToBlazorServerMigration.AspxFiles.cs

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,9 @@
1010
using CodeFactory.DotNet.CSharp;
1111
using CodeFactory.Formatting.CSharp;
1212
using CodeFactory.SourceCode;
13-
using AngleSharp.Dom;
14-
using AngleSharp.Html.Parser;
15-
using AngleSharp;
13+
1614
using System.ComponentModel.Design;
15+
using HtmlAgilityPack;
1716

1817
namespace WebFormsToBlazorServerCommands.Migration
1918
{
@@ -256,21 +255,21 @@ await _statusTracking.UpdateCurrentStatusAsync(MigrationStepEnum.AspxPages,
256255
/// </summary>
257256
/// <param name="elementToProcess"></param>
258257
/// <returns>String</returns>
259-
private async Task<string> ProcessSourceElement(Element elementToProcess)
258+
private async Task<string> ProcessSourceElement(HtmlNode elementToProcess)
260259
{
261-
Element processedElement = null;
260+
HtmlNode processedElement = null;
262261
StringBuilder processedHTML = new StringBuilder();
263262
var converterAdapter = new ConverterAdapter();
264263
converterAdapter.RegisterControlConverter(new AspxToBlazorControlConverter(converterAdapter));
265264

266-
var htmlParser = new AngleSharp.Html.Parser.HtmlParser();
265+
var htmlParser = new HtmlDocument();
267266

268267
try
269268
{
270269
//If this is an ASP:* control then call the migration code, append the *entire* migrated node, and return to the calling method.
271-
if (elementToProcess.LocalName.ToLower().Contains("asp:"))
270+
if (elementToProcess.Name.ToLower().Contains("asp:"))
272271
{
273-
var newNodeText = Task.Run(() => converterAdapter.MigrateTagControl(elementToProcess.LocalName, elementToProcess.OuterHtml)).Result;
272+
var newNodeText = await converterAdapter.MigrateTagControl(elementToProcess.Name, elementToProcess.OuterHtml);
274273

275274
//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
276275
return newNodeText;
@@ -280,26 +279,29 @@ private async Task<string> ProcessSourceElement(Element elementToProcess)
280279
//if the current element has children,
281280
// - add it to the targetDocumentFragment without the children attached
282281
// - recursively call this method to deal with the children, passing in the new appended as the parent element to append children too
283-
if (elementToProcess.ChildElementCount > 0)
282+
if (elementToProcess.ChildNodes.Count > 0)
284283
{
285-
processedElement = elementToProcess.Clone(false) as Element;
286-
foreach (Element item in elementToProcess.Children)
284+
//shallow clone
285+
processedElement = elementToProcess.CloneNode(false);
286+
287+
foreach (var item in elementToProcess.ChildNodes)
287288
{
288-
var newElement = htmlParser.ParseFragment(await ProcessSourceElement(item), processedElement);
289-
processedElement.Append(newElement.ToArray());
289+
var migratedValue = await ProcessSourceElement(item);
290+
var migratedChild = HtmlNode.CreateNode( migratedValue.Length > 0 ? migratedValue : " " );
291+
processedElement.AppendChild(migratedChild);
290292
}
291293
processedHTML.Append(processedElement.OuterHtml);
292294
} else
293295
{
294-
processedHTML.Append((elementToProcess.Clone(false) as Element).OuterHtml);
296+
processedHTML.Append((elementToProcess.Clone()).OuterHtml);
295297
}
296-
298+
297299
return processedHTML.ToString();
298300
}
299301
}
300-
catch (Exception)
302+
catch (Exception ex)
301303
{
302-
throw;
304+
throw ex;
303305
}
304306
}
305307

0 commit comments

Comments
 (0)