Converting from Webforms view engine to Razor–Some Tips
Recently, I have had to perform a lot of conversion in an MVC application from using the webforms view engine to the Razor view engine.
I say “had to” but we didn’t really have to, more wanted to. We wanted the cleaner syntax that razor allows. Since we were going to embark on a bunch of new features involving new pages, we wanted to do this conversion earlier rather than later to prevent excessive rework.
This post simply summarises most of the issues and tips that were experienced along the way and how we overcame them, so that others can get a clear picture of what is involved should they embark on such an undertaking, and be prepared for any issues.
Preparation
First off, there are some things you should do prior to starting the conversion to make the process as smooth as possible, and to allow easy resolution of any issues.
- Take a copy of your entire source tree and keep it separate to allow for comparison along the way. If you are using HG or GIT, clone your repository to another location. Sure you could look at source control history if you wanted, but its easier to have this code at hand to do side by side comparisons.More importantly though, you can run the backup version to compare HTML output to make sure your conversions are good.
- In your solution, turn on MVC compiled views. This will tell the compiler to compile your views and you will catch any errors whenever you compile. Very handy and saves sometime. Unfortunately, it does add some time to the build process. If you have a lot of views, this could be lengthy, so you may want to disable this after the conversion is complete. To enable compiled views:
- Right click on your project in solution explorer, and select Unload Project.
- One its unloaded, right click on it again and select ‘Edit Project. The project XML will load in the editor window.
- Locate the following
<MvcBuildViews>false</MvcBuildViews>
and change it to
<MvcBuildViews>true</MvcBuildViews>
- Save the file. Then right click on the project again and select ‘Reload Project’
- Now when you compile, your views will also be compiled.
- Download the aspx2razor conversion tool from Telerik which does a reasonable job of converting your ASPX views into razor views. It probably wont do it all for you,but it removes a good deal of work.
Performing the actual conversion
This is the easy part. Simply run the conversion tool over your project. You can do this by running the tool against your base views directory and have it recursively convert all files it founds in all directories to their razor counterparts. Something like this:
aspx2razor.exe c:\MyProject\MyViews\*.cshtml MyOutputDirectory -r
You will then need to copy the files from the output directory into your solution and ensure they are included in the project. Make sure you delete all the existing ASPX files as having both of these file types present can cause problems.
So that’s it. Job done right?
Testing and Fixing
Now the fun begins. The conversion tool works reasonably well, but it has its problems. Here are some of the issues you will find.
- The conversion tool does not support master pages, so don’t expect them to be converted. Roll up your sleeves and do those manually. Even though the tool does not support master pages, it will blindly convert anything you tell it to so it will attempt to convert a master page if one exists in the set of input files. Don’t be tempted to use a partially converted master page if there is one as it will usually not convert properly, putting in an incorrect ‘@inherits’ directive which just causes more confusion. Start from scratch and do the master pages manually.
- Sometimes the conversion tool completely misses the server side tags, particularly when embedded in script tags like this:
<script type="text/javascript" language="javascript" src="<%: Url.Content("~/Content/Scripts/jQuery/jshashtable.js") %>"></script>
- Embedded server tags can get completely messed up when converting to razor. As an example, the following snippet:
class="item <%: isParentDate ? "" : "child-date " %> <%: item.IsReconciled ? "reconciled " : "" %>">
gets converted to the following razor equivalent:
class="item @isParentDate ? "" : "child-date "@item.IsReconciled ? "reconciled " : """>
which is obviously incorrect and results in simple text being output to the HTML, not the expected class names. Ideally, this should be refactored into amore explicit code block, something like this:
@{ var divClass = string.Format("item {0}{1}", isParentDate ? string.Empty : "child-date ", item.IsReconciled ? "reconciled " : ""); } class="@divClass"
- “Tight” concatenation of server tags like this:
<input type="hidden" id="itemAmount<%: Model.BankFeed.Id %>" />
get converted to this:
<input type="hidden" id="itemAmount@Model.BankFeed.Id" />
which is not right and just renders the text. Again, something more explicit is required such as:
@{ var controlId = string.Format("itemAmount{0}", Model.Id); } <input type="hidden" id="@controlId" />
- One last tip. Use the “original” copy of your site and run it up in a browser, do the same with the converted site. For each view that is converted, it is worth doing a “source view” of original and converted page from the browser to ensure you are getting the same output. This is particularly important for scripts and CSS.
That is about it for most of the issues I came across. You will no doubt experience some variations from the examples above, but the set of issues presented here should at least allow you to be prepared for what the actual conversion effort is going to be.
Hopefully, this article helps you to efficiently convert your projects into the wonderful world of razor