Existe-t-il (ou existera-t-il) un outil pour convertir le balisage du moteur de vue WebForm (aspx) en balisage du moteur de vue Razor (cshtml)?
Réponses
Trop de publicités?Nous avons également été confrontés au problème de la conversion de nombreuses vues WebForms en Razor. Et devinez quoi, nous avons également mis au point un outil:
https://github.com/telerik/razor-converter
Il s'appuie également sur des expressions rationnelles (et pas mal d'entre elles) pour donner un sens au mumbo-jumbo WebForms, un peu comme l'outil de JohnnyO. Le nôtre pourrait couvrir quelques cas supplémentaires, mais ne me croyez pas sur parole et essayez-le à la place sur quelques vues.
Voici une simple Application de Console que j'ai écrit pour convertir les Formulaires web vues de Rasoir. Malheureusement, ce n'est pas l'épreuve des balles. J'ai converti environ 20 vues avec cela, et je suis la recherche que pour de simples points de vue, il est 100% correct, mais quand la vue est vraiment compliqué, la conversion n'est que d'environ 80% de réponses correctes. Même à 80%, c'est toujours mieux que d'avoir à recommencer depuis le début par la main.
Il y a certaines choses dans cet outil de conversion qui peuvent être spécifiques à la façon dont j'ai conçu mon WebForms vues, donc j'ai commenté il de sorte que vous pouvez le supprimer ou de le modifier.
Vous pouvez l'utiliser, par l'exécution de l'application console et en le passant dans un chemin d'accès au dossier ou le chemin du fichier. Si vous passez dans un dossier, il vous permet de convertir tous .aspx et .ascx fichiers dans le dossier (mais il ne sera pas recurse en sous-dossiers). Si vous passez dans un chemin de fichier, il suffira de convertir ce fichier. Une fois que c'est fait avec de la conversion, il va créer un nouveau .cshtml fichier avec le même nom que le .aspx ou .fichier ascx.
AVERTISSEMENT: Si vous possédez déjà un .cshtml fichier avec le même nom que le .aspx/.fichier ascx que vous tentez de convertir, cette application permet de remplacer l' .cshtml fichier lorsqu'il termine le .aspx/.ascx de conversion.
UTILISEZ À VOS PROPRES RISQUES. ASSUREZ-VOUS DE TOUT SAUVEGARDER AVANT D'UTILISER CET OUTIL.
Remarque: si votre aspx/fichier ascx est marqué en "lecture seule", vous obtiendrez une erreur car l'application de console ne sera pas en mesure de l'ouvrir. Assurez-vous que la lecture seule drapeau est désactivée sur tous aspx / ascx les fichiers que vous voulez 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);
}
}
}