Skip to content

Commit 732ffa8

Browse files
committed
Completed update for Migration Adapter Pattern
1 parent 7d5cc87 commit 732ffa8

File tree

7 files changed

+374
-73
lines changed

7 files changed

+374
-73
lines changed

src/WebFormsToBlazorServerCommands/Migration/AspxToBlazorControlConverter.cs

Lines changed: 186 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq;
4+
using System.Net.NetworkInformation;
45
using System.ServiceModel.Configuration;
56
using System.Text;
7+
using System.Text.RegularExpressions;
68
using System.Threading.Tasks;
9+
using AngleSharp;
10+
using AngleSharp.Dom;
11+
using AngleSharp.Html.Parser;
12+
using CodeFactory.Formatting.CSharp;
13+
using NLog.Targets.Wrappers;
714

815
namespace WebFormsToBlazorServerCommands.Migration
916
{
@@ -12,9 +19,12 @@ namespace WebFormsToBlazorServerCommands.Migration
1219
/// </summary>
1320
public class AspxToBlazorControlConverter : ControlConverterBase
1421
{
15-
public AspxToBlazorControlConverter(ITagControlConverter adapterHost):base(adapterHost)
22+
private static AngleSharp.IConfiguration _angleSharpConfig = AngleSharp.Configuration.Default;
23+
private static AngleSharp.IBrowsingContext _angleSharpContext = null;
24+
25+
public AspxToBlazorControlConverter(ITagControlConverter adapterHost) : base(adapterHost)
1626
{
17-
_TagsICanConvert = new List<string>();
27+
_TagsICanConvert = new List<string>();
1828

1929
_TagsICanConvert.Add("asp:listview");
2030
_TagsICanConvert.Add("asp:content");
@@ -39,9 +49,182 @@ public AspxToBlazorControlConverter(ITagControlConverter adapterHost):base(adapt
3949
_TagsICanConvert.Add("asp:datalist");
4050
_TagsICanConvert.Add("asp:datagrid");
4151
_TagsICanConvert.Add("asp:dropdownlist");
42-
52+
53+
_angleSharpContext = BrowsingContext.New(_angleSharpConfig);
54+
}
55+
56+
/// <summary>
57+
/// Class specific override of the baseclass ControlConverterBase
58+
/// </summary>
59+
/// <param name="tagName"></param>
60+
/// <param name="tagNodeContent"></param>
61+
/// <returns></returns>
62+
public override async Task<string> ConvertControlTag(string tagName, string tagNodeContent)
63+
{
64+
string _result = string.Empty;
65+
66+
switch (tagName.ToLowerInvariant())
67+
{
68+
case "asp:content":
69+
_result = await ConvertContentControl(tagNodeContent);
70+
break;
71+
72+
case "asp:formview":
73+
_result = await ConvertFormViewControl(tagNodeContent);
74+
break;
75+
76+
case "asp:editform":
77+
_result = await ConvertEditFormControl(tagNodeContent);
78+
break;
79+
80+
default:
81+
_result = await ConvertGenericControl(tagNodeContent);
82+
break;
83+
}
84+
85+
return _result;
86+
87+
}
88+
89+
#region Private conversion methods
90+
91+
/// <summary>
92+
/// This method is used to generically convert an asp control by removing the 'asp:'
93+
/// prefix from the control name and then returning the resultant content back to the caller.
94+
/// </summary>
95+
/// <param name="nodeContent"></param>
96+
/// <returns>converted control content</returns>
97+
private async Task<string> ConvertGenericControl(string nodeContent)
98+
{
99+
100+
try
101+
{
102+
int pos = nodeContent.IndexOf("asp:");
103+
if (pos < 0)
104+
{
105+
return nodeContent;
106+
}
107+
108+
return nodeContent.Substring(0, pos) + "" + nodeContent.Substring(pos + "asp:".Length);
109+
}
110+
catch (Exception ex)
111+
{
112+
113+
throw ex;
114+
}
115+
}
116+
117+
/// <summary>
118+
/// This method understands now to convert an asp:FormView control into a blazor equivalent.
119+
/// </summary>
120+
/// <param name="nodeContent"></param>
121+
/// <returns></returns>
122+
private async Task<string> ConvertFormViewControl(string nodeContent)
123+
{
124+
var model = await _angleSharpContext.OpenAsync(req => req.Content(nodeContent));
125+
var parser = new HtmlParser();
126+
127+
try
128+
{
129+
130+
var editFormNode = model.All.Where(p => p.LocalName.ToLower().Equals("asp:formview")).FirstOrDefault();
131+
var newNode = parser.ParseFragment($"<EditForm Model={editFormNode.GetAttribute("ItemType")} OnValidSubmit={editFormNode.GetAttribute("SelectMethod")}></EditForm>", editFormNode);
132+
133+
//this is now a live list having substituted the EditForm control for the old FormView one
134+
newNode.First().AppendNodes(editFormNode.ChildNodes.ToArray());
135+
136+
if (model.All.Any(p => p.TagName.ToLower().Equals("itemtemplate")))
137+
{
138+
//deal with itemtemplates... ??
139+
}
140+
141+
//send any child asp:* controls to be converted by the a call back out to the adapterHosting class.
142+
var aspFormTags = newNode.First().Descendents<IElement>().Where(p => p.NodeName.ToLower().Contains("asp:")).ToList();
143+
foreach (var formObj in aspFormTags)
144+
{
145+
var migratedControlText = await _adapterHost.MigrateTagControl(formObj.NodeName, formObj.OuterHtml);
146+
147+
var tempNode = parser.ParseFragment(migratedControlText, null);
148+
149+
//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.
150+
var appendElement = tempNode.GetElementsByTagName("BODY").First().ChildNodes;
151+
152+
formObj.Replace(appendElement.ToArray());
153+
}
154+
155+
return newNode.First().ToHtml();//.OuterHTML; // .ToString();
156+
}
157+
catch (Exception ex)
158+
{
159+
160+
throw ex;
161+
}
43162
}
44163

164+
/// <summary>
165+
/// This method understands how to convert an asp:EditForm control into a blazor equivalent.
166+
/// </summary>
167+
/// <param name="nodeContent"></param>
168+
/// <returns></returns>
169+
private async Task<string> ConvertEditFormControl(string nodeContent)
170+
{
171+
string _result = string.Empty;
172+
173+
try
174+
{
175+
//return content as-is for now.
176+
return nodeContent;
177+
}
178+
catch (Exception ex)
179+
{
180+
181+
throw ex;
182+
}
183+
}
45184

185+
/// <summary>
186+
/// This method is used to convert the asp:Content control to a Blazor equivalent. In this particular
187+
/// case - there is no equivalent. This control is the top-level asp:* container for a page and really just holds all other
188+
/// controls that are found in an *.aspx page definition.
189+
/// </summary>
190+
/// <param name="nodeContent"></param>
191+
/// <returns></returns>
192+
private async Task<string> ConvertContentControl(string nodeContent)
193+
{
194+
string _result = string.Empty;
195+
var parser = new HtmlParser();
196+
197+
try
198+
{
199+
var model = await _angleSharpContext.OpenAsync(req => req.Content(nodeContent));
200+
201+
var contentControlObj = model.Descendents<Element>().First(c => c.TagName.ToLower().Equals("asp:content"));
202+
203+
//send any child asp:* controls to be converted by the a call back out to the adapterHosting class.
204+
var aspFormTags = contentControlObj.Descendents<IElement>().Where(p => p.NodeName.ToLower().Contains("asp:")).ToList();
205+
foreach (var formObj in aspFormTags)
206+
{
207+
var migratedControlText = await _adapterHost.MigrateTagControl(formObj.NodeName, formObj.OuterHtml);
208+
209+
var tempNode = parser.ParseFragment(migratedControlText, null);
210+
211+
//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.
212+
var appendElement = tempNode.GetElementsByTagName("BODY").First().ChildNodes;
213+
214+
formObj.Replace(appendElement.ToArray());
215+
}
216+
217+
//There isn't any asp:content control equivalent in Blazor, so we'll just take the innerHTML
218+
_result = contentControlObj.InnerHtml;
219+
220+
return _result;
221+
}
222+
catch (Exception ex)
223+
{
224+
225+
throw ex;
226+
}
227+
}
228+
#endregion
46229
}
47230
}

src/WebFormsToBlazorServerCommands/Migration/ControlConverterBase.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace WebFormsToBlazorServerCommands.Migration
1212
/// </summary>
1313
public class ControlConverterBase : IControlConverter
1414
{
15-
private ITagControlConverter _adapterHost = null;
15+
internal ITagControlConverter _adapterHost = null;
1616
internal List<string> _TagsICanConvert = null;
1717

1818
public ControlConverterBase(ITagControlConverter adapterHost)
@@ -37,13 +37,13 @@ public ReadOnlyCollection<string> AvailableConversionTags
3737
/// <param name="tagName"></param>
3838
/// <param name="tagNodeContent"></param>
3939
/// <returns></returns>
40-
public string ConvertControlTag(string tagName, string tagNodeContent)
40+
public virtual async Task<string> ConvertControlTag(string tagName, string tagNodeContent)
4141
{
4242
StringBuilder _result = new StringBuilder();
4343

4444
try
4545
{
46-
46+
_result.Append(tagNodeContent);
4747

4848
return _result.ToString();
4949
}

src/WebFormsToBlazorServerCommands/Migration/ConverterAdapter.cs

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Collections.Generic;
22
using System.Linq;
3+
using System.Threading.Tasks;
34
using System.Windows.Documents;
45

56
namespace WebFormsToBlazorServerCommands.Migration
@@ -12,40 +13,61 @@ public class ConverterAdapter : ITagControlConverter
1213
private string _returnResult = string.Empty;
1314
private List<IControlConverter> _controlConverters = null;
1415

15-
public ConverterAdapter(List<IControlConverter> controlTagConverters)
16+
public ConverterAdapter()
1617
{
17-
_controlConverters = controlTagConverters;
1818
}
1919

20+
public bool RegisterControlConverter(IControlConverter converterObj)
21+
{
22+
try
23+
{
24+
if (_controlConverters == null)
25+
{
26+
_controlConverters = new List<IControlConverter>();
27+
}
28+
_controlConverters.Add(converterObj);
29+
30+
return true;
31+
}
32+
catch (System.Exception)
33+
{
34+
35+
return false;
36+
}
37+
38+
}
39+
40+
2041
/// <summary>
2142
/// This method takes an incoming tag/control and its inclusive text represention and returns the converted text.
2243
/// </summary>
2344
/// <param name="tagControlName"></param>
2445
/// <param name="tagNodeContent"></param>
2546
/// <returns>The converted text - otherwise a String.Empty if there is no converter registered for the passed in tagControlName</returns>
26-
public string MigrateTagControl(string tagControlName, string tagNodeContent)
47+
public async Task<string> MigrateTagControl(string tagControlName, string tagNodeContent)
2748
{
2849
string _returnResult = string.Empty;
2950

3051
try
3152
{
3253
if (string.IsNullOrEmpty(tagControlName) )
3354
{
34-
return
55+
return "nothing to convert.";
3556
}
3657

3758
//iterate over all of the IControlConverters that have been registerd and find the
3859
//*first* one that knows how to convert the passed in tag
3960

4061
//check if control is available to be converted from IControlConverter
41-
if (!_tagConverter.AvailableConversionTags.Contains(tagControlName))
62+
foreach (var registerdConverter in _controlConverters)
4263
{
43-
return tagNodeContent;
64+
if (registerdConverter.AvailableConversionTags.Contains(tagControlName.ToLower()))
65+
{
66+
//Call migration logic from specific class
67+
_returnResult = await registerdConverter.ConvertControlTag(tagControlName, tagNodeContent);
68+
}
4469
}
4570

46-
//Call migration logic from specific class
47-
_returnResult = _tagConverter.ConvertControlTag(tagControlName, tagNodeContent);
48-
4971
return _returnResult;
5072
}
5173
catch (System.Exception)

src/WebFormsToBlazorServerCommands/Migration/IControlConverter.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Collections.Generic;
22
using System.Collections.ObjectModel;
3+
using System.Threading.Tasks;
34

45
namespace WebFormsToBlazorServerCommands.Migration
56
{
@@ -18,5 +19,6 @@ public interface IControlConverter
1819
/// </summary>
1920
/// <param name="tagName"></param>
2021
/// <param name="tagNodeContent"></param>
21-
string ConvertControlTag(string tagName, string tagNodeContent)
22+
Task<string> ConvertControlTag(string tagName, string tagNodeContent);
23+
}
2224
}

src/WebFormsToBlazorServerCommands/Migration/ITagControlConverter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public interface ITagControlConverter
1414
/// <param name="tagControlName"></param>
1515
/// <param name="tagNodeContent"></param>
1616
/// <returns>The converted/migrated string content of the TagControl. It is entirely possible that the return NodeText will have overridded the TagControlName into something else entirely. ie. a Blazor control</returns>
17-
string MigrateTagControl(string tagControlName, string tagNodeContent);
17+
Task<string> MigrateTagControl(string tagControlName, string tagNodeContent);
1818

1919
}
2020
}

0 commit comments

Comments
 (0)