Updating a VB.NET ASP.NET Web Application Project to support C# and MVC - Webnames Blog

Updating a VB.NET ASP.NET Web Application Project to support C# and MVC

A Case Study/Guide

Background and Goal

Our corporate website was built primarily using VB.NET ASP.NET Web Forms. We have done a good job of keeping up with the features of the latest .NET framework releases, and we are happy with the power and readability of VB.NET (it’s extremely similar to C# in most respects).

However, most of our newer developers are more familiar with C#, and the C# community for code samples and other resources is much larger than the VB.NET community. We write all our newer background processes in C#, and we wanted the same for our web site. We also wanted to adopt ASP.NET MVC to enjoy the control and flexibility it offers.

The Challenge

Integrating MVC into an existing Web Forms project is possible, and there are multiple guides (I like Scott Zischerk’s) to take you through the configuration and references you will need to change.

The bigger challenge for us was that are actually two kinds of ASP.NET Web Forms projects: Web Application Projects (WAP) and Web Site Projects (WSP). Our site was configured as a Web Application Project, which means that all its code-behind was compiled to a single .NET assembly (DLL). In .NET, you cannot mix two languages in one DLL. To use C# in our WAP we would have had to convert the entire site, all 600,000+ lines of code. While there are many good VB.NET to C# conversion tools out there, if you have used any, you know that even a 99% correct conversion requires a lot of manual effort from a developer to reach 100%. There is no way we could have justified to management the hundreds of development hours required for such a task.

At the same time, we wanted the new MVC pages we developed to be as tightly integrated as possible with the existing site, so we wanted to avoid a multi-project solution where each new MVC controller required its own new child project under the main application. Even the venerable gurus on Stack Overflow had few appealing suggestions when I posed our problem.

I knew that if I could convert our project from a WAP to a WSP, we would be able to use C# for new MVC pages while leaving the existing VB.NET Web Forms pages intact. (And performance would not suffer, as the MSDN link above attests.) Unfortunately, after hours of searching, I could not find a comprehensive guide for converting a WAP to a WSP (there were dozens of guides for the reverse process.)

The Solution

Captian Picard gleefully says 'Technobabble makes it so.'I eventually got it done through painful trial and error, and I document the technobabble here for anyone who comes across this scenario in the future. Note that not all the steps below will necessarily be required for your particular project.

  • Backup your project first! When documenting these steps, I revised my procedure several times using an offline copy of the site. That way, once I had all the kinks ironed out, I could quickly check out the latest version of all our project files from source control, follow the procedure, and check them back in with minimal disruption to my team.
  • Delete the main project DLL from the bin folder. This will help you verify that your conversion has succeeded (all code should be dynamically compiled from now on.)
  • In all .ascx, .aspx, .asax, and .Master files, replace CodeBehind=” with CodeFile=”.
  • I found that many assembly and intra-project references had to be adjusted, particularly with regard to references between pages and fully-qualified vs. non-fully-qualified namespaces.
    • For example, if a page referenced a public method or class exposed in another code-behind page, I had to remove our project’s fully-qualified namespace prefix www.webnames.ca.
    • Occasionally such methods were declared as Friend Shared or Friend Function which was OK when they were in the same WAP DLL, but now that they would be compiled separately in a WSP, they had to be changed to Public Shared or Public Function.
    • Add reference directives ( <%@ Reference Page/Control=”” %> ) to pages that refer to other pages or User Controls.
    • I also had to manually add these .NET framework assembly references to the web.config file under / configuration/system.web/compliation/assemblies:
      <add assembly=”System.Data.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089″/>
      <add assembly=”System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a”/>
      <add assembly=”System.Collections, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a”/>
      <add assembly=”System.Transactions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089″/>
      And this global namespace under /configuration/system.web/pages/namespaces:

      <add namespace=”System.Data”/>

  • We had several common classes defined under various custom folders, such as one we called App_Class. This was fine for a WAP because they could be namespaced and marked as compilable, but in a WSP they had to all be moved under App_Code.
  • Occasionally we had code in App_Code that needed to access a User Control to dynamically instantiate it, or access a Master Page to refer to a public method. This was not easily achievable in a WSP because the @Reference directive mentioned above only works in markup files, not code files. The admittedly ugly workaround was to copy the code-behind files (.ascx.vb, .Master.vb and .designer.*) to a folder under App_Code, leaving the markup files (.ascx, .Master) where they were. In the markup files I removed the CodeFile= attributes entirely.
  • I had to move the code-behind of .asmx.vb web service files into their corresponding markup files (.asmx) and deleted the code-behind files and CodeFile=” attributes.
  • The .designer files are unnecessary in a WSP, so I deleted all of them that were not required to exist under App_Code as explained above. That happily put an end to a common source of grief under WAP’s.
  • In this process I found a handful of pages that were actually completely broken, which we knew nothing about. They were referencing the wrong code-behind file, or using the wrong class name, etc. These can be identified by doing a Rebuild Web Site in Visual Studio. The nice thing about a WSP build is that it has to fully compile and verify the markup pages because there are no designer files to generate the controls needed by the code-behind, so you can catch more issues before you deploy.
  • I followed Scott Zischerk’s guide to integrate MVC, and verified that C# controllers could work by creating a subfolder under App_Code called CSharp, supported by the following addition to the /compilation node of web.config:

    <codeSubDirectories>
    <add directoryName=”CSharp”/>
    </codeSubDirectories>

  • I found that the “default document redirection” to Default.aspx pages across the site had broken for some reason due to MVC routing, so I wrote some custom code in the Global.asax.vb.Application_Error() method to compensate. Basically it traps 404 errors and attempts to redirect to a Default.aspx page in the same folder before returning a 404.
  • Notes on automated builds and deployments:
    • Rather than going through the hassle of configuring a complicated MSBuild project file, I simply added the following line to our existing build script to call Visual Studio and perform the full Rebuild/Verify Website step:

      C:Program Files (x86)Microsoft Visual Studio 12.0Common7IDEdevenv.com” “!SC_PATH!www.webnames.ca.sln” /Rebuild !BUILDCONFIGURATION! /out !LOGFILE! >> !LOGFILE! 2>&1

    • You cannot make DLL references in a WSP as you can in a WAP. Generally you just have to copy everything you need into the bin folder. Unfortunately this makes it trickier for a site like ours that has multiple references to separate DLL projects. When those DLL’s are rebuilt, we want the site to grab their latest versions before it builds itself. To accomplish this I emptied the bin folder and then made .refresh files for DLL’s that referenced our local projects. That technique allows us to do full rebuilds from within Visual Studio without resorting to our build script.

Conclusion

We have been running our site using this format for several months now without any major issues. It has allowed us to modernize our development language and framework without spending hundreds of hours rewriting legacy code.

Share this:

Posted in:

Developer's Corner