2010-10-16 10 views

Respuesta

36

Nosotros también enfrentamos el problema de convertir muchas vistas de WebForms a Razor. Y adivina qué, también hemos llegado con una herramienta:

https://github.com/telerik/razor-converter

También se basa en expresiones regulares (y un buen número de ellos) para dar sentido a la WebForms galimatías, al igual que la herramienta por JohnnyO. La nuestra podría cubrir algunos casos más, pero no confíe en mi palabra y pruébelo en algunas vistas.

+1

Esto funcionó bien para mí. ¡Gracias por compartir! –

+0

Gracias por esta útil herramienta. Un problema que encontré fue que los comentarios de mi servidor se eliminaron durante la conversión. Sería bueno tenerlos convertidos a la sintaxis '@ * ... * @'. –

+0

Indeed :) Arreglaremos esto –

10

Aquí hay una aplicación de consola simple que escribí para convertir vistas de WebForms a Razor. Lamentablemente, no es a prueba de balas. He convertido aproximadamente 20 vistas con esto, y estoy descubriendo que para vistas simples, lo hace 100% correcto, pero cuando la vista se vuelve realmente complicada, la conversión es solo aproximadamente 80% correcta. Incluso al 80%, es mejor que tener que empezar desde el principio a mano.

Hay algunas cosas en esta herramienta de conversión que pueden ser específicas de cómo diseñé mis vistas de WebForms, así que lo comenté para que pueda eliminarlo o personalizarlo.

Puede usarlo ejecutando la aplicación de consola y pasando una ruta de carpeta o de archivo. Si pasa una carpeta, convertirá todos los archivos .aspx y .ascx en la carpeta (pero no volverá a aparecer en las subcarpetas). Si pasa en una ruta de archivo, solo convertirá ese archivo. Una vez hecho esto con la conversión, creará un nuevo archivo .cshtml con el mismo nombre que el archivo .aspx o .ascx.

ADVERTENCIA: si ya tiene un archivo .cshtml con el mismo nombre que el archivo .aspx/.ascx que está intentando convertir, esta aplicación sobrescribirá el archivo .cshtml cuando complete el archivo .aspx /. conversión de ascx

UTILÍCELO BAJO SU PROPIO RIESGO. ASEGÚRESE DE RESPALDAR TODO ANTES DE UTILIZAR ESTA HERRAMIENTA.

Nota: si su archivo aspx/ascx está marcado como "solo lectura", obtendrá un error porque la aplicación de la consola no podrá abrirlo. Asegúrese de que el indicador de solo lectura esté desactivado en todos los archivos aspx/ascx que intente convertir.

class Program { 
    private readonly static string razorExtension = ".cshtml"; 

    /// <summary>Usage: RazorConverter.exe "C:\Files" or RazorConverter.exe "C:\Files\MyFile.aspx"</summary> 
    static void Main(string[] args) { 

     if (args.Length < 1) 
      throw new ArgumentException("File or folder path is missing."); 
     string path = args[0]; 

     List<string> convertedFiles = new List<string>(); 
     Regex webFormsExtension = new Regex(".aspx$|.ascx$"); 
     if (Directory.Exists(path)) { 
      foreach (var file in Directory.GetFiles(path, "*.aspx")) { 
       var outputFile = webFormsExtension.Replace(file, razorExtension); 
       ConvertToRazor(file, outputFile); 
       convertedFiles.Add(file); 
      } 

      foreach (var file in Directory.GetFiles(path, "*.ascx")) { 
       var outputFile = webFormsExtension.Replace(file, razorExtension); 
       ConvertToRazor(file, outputFile); 
       convertedFiles.Add(file); 
      } 
     } else if (File.Exists(path)) { 
      var match = webFormsExtension.Match(path); 
      if (match.Success) { 
       ConvertToRazor(path, webFormsExtension.Replace(path, razorExtension)); 
       convertedFiles.Add(path); 
      } else { 
       throw new ArgumentException(String.Format("{0} file isn't a WebForms view", path)); 
      } 
     } else { 
      throw new ArgumentException(String.Format("{0} doesn't exist", path)); 
     } 

     Console.WriteLine(String.Format("The following {0} files were converted:", convertedFiles.Count)); 
     foreach (var file in convertedFiles) { 
      Console.WriteLine(file); 
      } 
    } 

    private static void ConvertToRazor(string inputFile, string outputFile) { 

     // Known Bug: when writing anything directly to the response (other than for HTML helpers (e.g. Html.RenderPartial or Html.RenderAction)), 
     // this Converter will not correctly generate the markup. For example: 
     // <% Html.RenderPartial("LogOnUserControl"); %> will properly convert to @{ Html.RenderPartial("LogOnUserControl"); } 
     // but 
     // <% MyCustom("Foo"); %> will incorrectly convert to @MyCustom("Foo"); 

     string view; 
     using (FileStream fs = new FileStream(inputFile, FileMode.Open)) 
     using (StreamReader sr = new StreamReader(fs)) { 
      view = sr.ReadToEnd(); 
     } 

     // Convert Comments 
     Regex commentBegin = new Regex("<%--\\s*"); 
     Regex commentEnd = new Regex("\\s*--%>"); 
     view = commentBegin.Replace(view, "@*"); 
     view = commentEnd.Replace(view, "*@"); 

     // Convert Model 
     Regex model = new Regex("(?<=Inherits=\"System.Web.Mvc.ViewPage<|Inherits=\"System.Web.Mvc.ViewUserControl<)(.*?)(?=>\")"); 
     Regex pageDeclaration = new Regex("(<%@ Page|<%@ Control).*?%>"); 
     Match modelMatch = model.Match(view); 
     if (modelMatch.Success) { 
      view = pageDeclaration.Replace(view, "@model " + modelMatch.Value); 
     } else { 
      view = pageDeclaration.Replace(view, String.Empty); 
     } 

     // TitleContent 
     // I'm converting the "TitleContent" ContentPlaceHolder to View.Title because 
     // that's what TitleContent was for. You may want to ommit this. 
     Regex titleContent = new Regex("<asp:Content.*?ContentPlaceHolderID=\"TitleContent\"[\\w\\W]*?</asp:Content>"); 
     Regex title = new Regex("(?<=<%:\\s).*?(?=\\s*%>)"); 
     var titleContentMatch = titleContent.Match(view); 
     if (titleContentMatch.Success) { 
      var titleVariable = title.Match(titleContentMatch.Value).Value; 
      view = titleContent.Replace(view, "@{" + Environment.NewLine + " View.Title = " + titleVariable + ";" + Environment.NewLine + "}"); 
      // find all references to the titleVariable and replace it with View.Title 
      Regex titleReferences = new Regex("<%:\\s*" + titleVariable + "\\s*%>"); 
      view = titleReferences.Replace(view, "@View.Title"); 
     } 

     // MainContent 
     // I want the MainContent ContentPlaceholder to be rendered in @RenderBody(). 
     // If you want another section to be rendered in @RenderBody(), you'll want to modify this 
     Regex mainContent = new Regex("<asp:Content.*?ContentPlaceHolderID=\"MainContent\"[\\w\\W]*?</asp:Content>"); 
     Regex mainContentBegin = new Regex("<asp:Content.*?ContentPlaceHolderID=\"MainContent\".*?\">"); 
     Regex mainContentEnd = new Regex("</asp:Content>"); 
     var mainContentMatch = mainContent.Match(view); 
     if (mainContentMatch.Success) { 
      view = view.Replace(mainContentMatch.Value, mainContentBegin.Replace(mainContentEnd.Replace(mainContentMatch.Value, String.Empty), String.Empty)); 
     } 

     // Match <%= Foo %> (i.e. make sure we're not HTML encoding these) 
     Regex replaceWithMvcHtmlString = new Regex("<%=\\s.*?\\s*%>"); // removed * from the first <%=\\s.*?\\s*%> here because I couldn't figure out how to do the equivalent in the positive lookbehind in mvcHtmlStringVariable 
     Regex mvcHtmlStringVariable = new Regex("(?<=<%=\\s).*?(?=\\s*%>)"); 
     // Match <%, <%: 
     Regex replaceWithAt = new Regex("<%:*\\s*"); 
     // Match %>, <% (but only if there's a proceeding }) 
     Regex replaceWithEmpty = new Regex("\\s*%>|<%\\s*(?=})"); 

     var replaceWithMvcHtmlStrings = replaceWithMvcHtmlString.Matches(view); 
     foreach (Match mvcString in replaceWithMvcHtmlStrings) { 
      view = view.Replace(mvcString.Value, "@MvcHtmlString.Create(" + mvcHtmlStringVariable.Match(mvcString.Value).Value + ")"); 
      } 

     view = replaceWithEmpty.Replace(view, String.Empty); 
     view = replaceWithAt.Replace(view, "@"); 

     Regex contentPlaceholderBegin = new Regex("<asp:Content[\\w\\W]*?>"); 
     Regex contentPlaceholderId = new Regex("(?<=ContentPlaceHolderID=\").*?(?=\")"); 
     Regex contentPlaceholderEnd = new Regex("</asp:Content>"); 
     MatchCollection contentPlaceholders = contentPlaceholderBegin.Matches(view); 
     foreach (Match cp in contentPlaceholders) { 
      view = view.Replace(cp.Value, "@section " + contentPlaceholderId.Match(cp.Value).Value + " {"); 
     } 
     view = contentPlaceholderEnd.Replace(view, "}"); 

     // if we have something like @Html.RenderPartial("LogOnUserControl");, replace it with @{ Html.RenderPartial("LogOnUserControl"); } 
     Regex render = new Regex("@Html\\.\\S*\\(.*\\)\\S*?;"); 
     var renderMatches = render.Matches(view); 
     foreach (Match r in renderMatches) { 
      view = view.Replace(r.Value, "@{ " + r.Value.Substring(1) + " }"); 
     } 


     using (FileStream fs = new FileStream(outputFile, FileMode.Create)) { 
      byte[] bytes = Encoding.UTF8.GetBytes(view); 
      fs.Write(bytes, 0, bytes.Length); 
     } 
    } 
} 
2

Los usuarios de ReSharper pueden votar por una característica para convertir automáticamente de aspx a cshtml. ReSharper tendrá una representación AST para ambos lados, por lo que podrían (en teoría) hacer un trabajo muy sólido sin requerir expresiones regulares.

http://youtrack.jetbrains.net/issue/RSRP-194060

Cuestiones relacionadas