11using System ;
22using System . Collections . Generic ;
33using System . Linq ;
4+ using System . Net . NetworkInformation ;
45using System . ServiceModel . Configuration ;
56using System . Text ;
7+ using System . Text . RegularExpressions ;
68using 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
815namespace 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}
0 commit comments