Li Chen's Blog

  • ASP Classic Compiler is now open source

    After weeks of preparation, I have opened the source code for my ASP Classic Compiler under the Apache 2.0 license. I conceived the project in 2009 when I joint a company that had a large amount of ASP Classic code. The economy was very slow at the time so I had some energy left to start the work as a hobby. As the economy recovers, I was getting busier with my day-time job. We converted most of our ASP Classic code to .net so that this project would no longer be useful for my own use. However, I truly hope that this project will be useful to those who can still use it.

    The project had gone a long way to implement most features in the VBScript 3.0 standard. It is capable of running the Microsoft FMStock 1.0 end to end sample application. I chose VBScript 3.0 in my initial implementation because VBScript 3.0 is a language with dynamic type and static membership. ASP Classic Compiler is faster than most of the Javascript implementations and is about 3 times faster than the IIS ASP interpreter in limited benchmark test. Many users have requested VBScript 5.0 features such as Class, Execute and Eval. VBScript 5.0 has dynamic membership like Javascript. To avoid the performance hit, I have done some research to optimize the performance for the mostly static scenariou, but have yet to find time to implement it.

    For this project to be successful, I truly need community involvement. In the next few days, I will outline what need to be done. I will stay as the project lead until we find a suitable new leader.

  • New VB.NET Syntax since VS2005

    I have not used VB.NET seriously after VS2003. Recently, I had to maintain an old VB.NET application so I had to spend a bit time to find out the VB equivalent of new C# syntax introduced in VS2005 or later:

    Category C# VB.NET
    Generics List<string> List(Of String)
    Object Initializer new Person() { First=”a”, Last=”b” } New Person() With {.First = “a”, .Last = “b” }
    Anonymous Type var a = new { First=”a”, Last=”b” }; Dim a= New With {.First = “a”, .Last = “b” }
    Array or Collection Initializer int[] a = {0, 2, 4, 6, 8};
    or
    int[] a = new int[] {0, 2, 4, 6, 8};
    Dim a() as Integer = {0, 2, 4, 6, 8}
    or
    Dim a() as Integer = New Integer()  {0, 2, 4, 6, 8}
    Dictionary Initializer Dictionary<int, string> d = {{1, "One"}, {2, "Two"}}; Dim d As Dictionary(Of Integer, String) = {{1, "One"}, {2, "Two"}}
    Lambda Expression x => x * x function(x) x*x
    Multiline Lambda Expression (input parameters) => {statements;} function(input parameters) 
        statements
    end function
  • Relating software refactoring to algebra factoring

    Refactoring is a fairly common word in software development. Most people in the software industry have some ideas of it. However, it was not clear to me where the term comes from and how it relates to the factor we learnt in algebra. A Bing search indicates that the word Refactoring origin from Opdyke’s Ph.D. thesis used for restructuring in object oriented software, but is not clear how it relates to the factor we normally know. So I attempt to make some sense out of it after the fact.

    In algebra, we know a factor is part that participated in a multiplication. For example, if C = A * B, we call A and B factors of C.

    Factors are often used to simplify computation. Taking the reverse distribution identity of multiplication as an example, C * A + C * B can be rewritten as C * (A + B). This will improve computational efficiency if multiplication is far more expensive than addition. C in this case is called the common factor in the two terms, C * A and C * B. If there are no common factors between A and B, we call C the greatest common factor (GCF) the two terms.

    To identify the GCF of two numbers, we usually find all the prime factors of numbers and include the greatest common count of those prime factors. For example, if we want to find the GCF of 72 and 120, we would like 72 as 23 * 32 and 120 as 23 * 31 * 51. Then the GCF would be 23 * 31 = 24. (Note that in real computer program we usually calculate GCF using Euclid’s algorithm).

    Now let us see an example of analogy to algebra factoring in Boolean algebra. There is an identity (A and B) or (A and C) = A and (B or C). If we relate “and” to * and “or” to +, the above identity would be very similar to distribution identity in algebra.

    In software refactoring, we usually identify the longest common sequence that is duplicated (let me set parameterization aside for simplicity) and try to reuse the sequence as a single unit. How do we find an analogy to algebra? Let us consider an instruction in a sequence as a function that take the state of computer as input and return the modified state. Then a sequence of instructions can be written as f1(f2(f3(…fn()))). If we replace the () symbol with *. Then we can write above as f1 * f2  * f3 *  …  * fn. Now we use + to denote any situation that we need branching. For example, we could write if (cond) { A } then { B } as A + B. Now let use apply this notation to a more complex example:

    if (cond) {
    	A;
    	B;
    	C;
    } else {
    	D;
    	B;
    	E;
    }

    A to E above are block of code. So using the above notation, we can rewrite it as A * B * C + D * B * E. Now if we try to factor this expression, we get (A + D) * B * (C + E) (Note that this is a bit different to normal Algebra factoring). Now we expand the above expression into code, we would get something like:

    if (cond) {
    	A;
    } else {
    	D;
    }
    
    B;
    
    if (cond) {
    	C;
    } else {
    	E;
    }

    That is in fact one of fairly common types of refactoring.

  • Teaching high school kids ASP.NET programming

    During the 2011 Microsoft MVP Global Summit, I have been talking to people about teaching kids ASP.NET programming. I want to work with volunteer organizations to provide kids volunteer opportunities while learning technical skills that can be applied elsewhere. The goal is to teach motivated kids enough skill to be productive with no more than 6 hours of instruction. Based on my prior teaching experience of college extension courses and involvement with high school math and science competitions, I think this is quite doable with classic ASP but a challenge with ASP.NET. I don’t want to use ASP because it does not provide a good path into the future. After some considerations, I think this is possible with ASP.NET and here are my thoughts:

    · Create a framework within ASP.NET for kids programming.

    · Use existing editor. No extra compiler and intelligence work needed.

    · Using a subset of C# like a scripting language. Teaches data type, expression, statements, if/for/while/switch blocks and functions. Use existing classes but no class creation and OOP.

    · Linear rendering model. No complicated life cycle.

    · Bare-metal html with some MVC style helpers for widget creation; ASP.NET control is optional. I want to teach kids to understand something and avoid black boxes as much as possible.

    · Use SQL for CRUD with a helper class. Again, I want to teach understanding rather than black boxes.

    · Provide a template to encourage clean separation of concern.

    · Provide a conversion utility to convert the code that uses template to ASP.NET MVC. This will allow kids with AP Computer Science knowledge to step up to ASP.NET MVC.

    Let me know if you have thoughts or can help.

  • Migrating a large web application to ASP.NET MVC

    Recently I had the luck of migrating some classic ASP pages to ASP.NET MVC. I would share some of the experiences below.

    ASP.NET webform and ASP.NET MVC can coexist just fine

    We have a huge existing ASP.NET webform application with thousands of pages. The challenge therefore is that any addition developed using ASP.NET should not affect the operation of existing webform pages. The mixing of ASP.NET Webform and MVC has been studied previously by many people. It is fairly easy to find some articles by searching “asp.net mvc and webforms together” on your favorite search engine. Basically, we need to include 3 additional DLLs in the web application:

    • System.Web.Routing
    • System.Web.Abstractions
    • System.Web.Mvc

    The System.Web.Routing is not part of ASP.NET MVC, but is used by MVC to route a web request to a controller. The System.Web.Abstractions add a wrapper to some built-in asp.net classes such as Request, Response, Session to decouple MVC code from the ASP.NET built-in classes so that these classes can be mocked in testing projects.

    The first step to enable routing is to add the URLRoutingModule to the list of HTTP Modules in web.config:

    <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule,System.Web.Routing, Version=3.5.0.0,Culture=neutral, PublicKeyToken=31BF3856AD364E35" />

    The next step is to configure the route. In order not to interfere with the operation of existing asp.net pages, we want to exclude all of them from routing in global.asax:

    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.IgnoreRoute("{resource}.aspx/{*pathInfo}");

    routes.IgnoreRoute("{resource}.asmx/{*pathInfo}");

    routes.IgnoreRoute("{resource}.svc/{*pathInfo}");

    routes.IgnoreRoute("{resource}.ashx/{*pathInfo}");

    AreaRegistration.RegisterAllAreas();

    In the last line, we used an ASP.NET feature called Areas that I will discuss later.

    The third step is to add a bunch of namespaces to <Pages> in web.config so that some MVC namespaces can be used in MVC view pages. We skipped this step because we do not want to affect the existing pages with bunch of new namespaces. We will do this as part of the Area implementation.

    ASP.NET MVC allows 100% of the code in the library DLLs

    In order to allow developers work independently, we actually split the application into multiple web applications. By default, ASP.NET MVC project put models, views and controllers in a single project. It is in fact very easy to move models and controllers into a separate library DLL, leaving the web application project only the view pages. On deployment, we simply deploy the DLLs to the bin directory of the application root, and the view pages into directories under the Areas folder (see below).

    The ASP.NET MVC Areas feature is one of the best feature in MVC 2 for large projects

    There are many resources about MVC Areas on the internet. For example, one can read Phil Haack’s original article on the subject. With areas, the responsibility for registering route is delegated to a subclass of AreaRegistration which now lives in our library project. When AreaRegistration.RegisterAllAreas() is called, ASP.NET will search for all AreaRegistration subclasses in all assemblies in the bin dir so that we do not have to modify the global.asax when we add new areas.

    In the AreaRegistration subclass, we would do something like:

    public override void RegisterArea(AreaRegistrationContext context)

    {

    context.MapRoute(

    "Services",

    "Sub1/Sub11/Sub111/{controller}.mvc/{action}/{id}",

    new { action = "Index", id = "" },

    new string[] { "My.Custom.Namespace.Controllers" }

    );

    }

    Note that we use an optional parameter to route the request to the controllers under particular namespace so that we can retain our existing namespace structure. Also, this approach allows us to blend the new mvc URLs into the existing application URLs very well.

    Our web applications are only left with views. We just need to deploy these views to the web server under appropriate area directories. This is how an Areas directory may look like:

    image

    Note that we have a web.config in the Areas directory? That is the place we add a HttpNotFoundHandler to protect all the views from getting accessed directly. We also add the appropriate attributes, and namespaces to the <Pages> element so that we apply these configurations only to the view pages.

    Summary

    In summary, ASP.NET MVC allows us to put 100% of code into many library dlls that can be independently developed. The areas feature allows us to delegate the responsibility of route registration to each individual dll as well as centrally apply namespaces and attributes to view pages without affecting the existing asp.net webform pages.

  • PublicSettingsSingleFileGenerator

    I added a Settings.settings file in one of my library project and I want to use the settings in my ASP.NET application. Unfortunately, the Settings class in Settings.Designer.cs is created as internal sealed partial class so that my ASP.NET application in a different assembly cannot see the class. Fortunately, to make the Settings class public, all I need to to is to go to the properties of Settings.settings file and change the Custom Tool from SettingsSingleFileGenerator to PublicSettingsSingleFileGenerator.

  • System.ComponentModel.DataAnnotation talk at LA Code Camp

    Today, I gave a talk at LA code camp on using Validation Attributes in the System.ComponentModel.DataAnnoation namespace in the context of both ASP.NET MVC and other applications.

    Since .net 3.5 does not have a Validator class, I have supplied a Validator class in the attached code. In addition, I have also presented a data structure that can be constructed dynamically to stored the validation attributes for classes and properties, and a dynamic validator that consume the data structure.

    Validation.Zip

  • Awarded Microsoft ASP/ASP.NET MVP

    Since I became an MCSD charter member in 1995, I finally reached a new height in my career. I had a physics major, but I was very fascinated by computer when I got my PC. I only took a C++ course in college; at that time C++ “compiler” was still a C translator. The class project was to write a C++ pretty printer; that is how I learnt parsing and data structure. I immediately applied the knowledge to my first consulting assignment. My client wants to rewrite a DOS program to a Windows program, but the company that wrote the DOS program would not give them the source code. Fortunately, all the data in the program is available through several reports so my assignment was to parse the printer language so that I can extract the data. In 1995 to 1996, I wrote a VBA like interpreter and a mini web browser, all in 16 bit VB3. In 1995, I was also invited to Redmond to write the Microsoft Access 95 exam. Then I worked comfortably for a insurance software company for 9 years.

    In 2006, I had a chance to work with a very innovative team at ESRI. There I was able to apply my parser skill again on a very innovative project called Site Builder. It is essentially a wizard that can generate a map website like Windows Live map. What makes it interesting is that it can reverse engineering an existing website by parsing ASP.NET pages to extract information and allow user to modify the website through the wizard.

    In 2007, I returned to the insurance industry. I noticed that due to various cross-cutting requirements, developers often turn a one page rating spec into 3000-5000 lines of code. There I started experiment with domain specific language (DSL). I was able to express the rating logic in only 20-30 lines of code, with almost one-to-one correspondence to the written spec. Then I can execute the DSL with a runtime that has only about 600 lines of code. Any new cross-cutting requirement can be implemented in the templates. As the company was moving from Microsoft technology to Java, I was sent to the Java team. There I worked with Struts, Spring and Hibernate. Although I quickly gained 3 Java certifications in a few months, I felt I missed .NET. I would say simply piling up best frameworks and best practices would often lead to bloated rather than best software.

    In 2008, I joined an insurance software vendor that is a .Net shop. The shop still has a large number of classic asp pages. So I started writing ASP Classic Compiler using Microsoft dynamic language runtime (DLR). My previous experience with Struts allows me to exam ASP.NET MVC very thoroughly. I am very glad that ASP.NET MVC, through several quick iteration, has exceeded Struts. I am very glad that ASP.NET MVC has made effort to reduce repetitive code. For example, you can just add a few DataAnnotation attributes to the entity, the validation rule can even propagate to the client Javascript code! I also like to see the new generation of user-friendly tools like LightSwitch. I was slightly disappointed that LightSwitch was tightly coupled to Silverlight. I was hoping there would be an abstraction on top of the actually WPF classes. This way the tool could not only generate the desktop software, but also true Web AJAX application; I think both Google Web Toolkit (GWT) and Script# has demonstrated its feasibility. We have been changing UI frameworks too often. If the tool put reasonable abstraction over the UI and tier, developers just need to fill business logic in a few places in the template. The build system can then generate whether we want desktop, web or a new type application that we are not even aware of today. If we have been working with a more abstracted toolkit, we could probably work with the tool for much longer than jumping through different frameworks.

  • My first real-world experience with Web Client Software Factory (WCSF)

    Introduction

    WCSF has existed since January 2007. Although I looked at it before, this is the first time I used it in a real project. Since ASP.NET MVC has been available, a frequent question for a development team is the choice between WCSF or MVC. I would not comment on how our team arrived the decision but will comment on the comparison at the end of this post. In this post, I will attempt to document what I learnt, both for myself and for anyone who encounter the similar situation.

    What is WCSF

    Web Client Software Factory (WCSF) is an application framework that works with Microsoft ASP.NET webform. In a typical webform application, there is a significant amount of logic in the code behind file that takes input from request, server controls and call business components. The the code would set the state of the server components or redirect to another URL based on the return of business components. The code is also responsible for reading and setting the states such as session, application and viewstate. The most important objective of WCSF is to separate the logic from the code behind file into the module project as much as possible so that these logic can be tested using Visual Studio test project or another testing framework such as NUnit.

    WCSF projects can be created using a WCSF Visual Studio extension. The new extension contains a new WCSF solution template:

    image

    Once the solution is created, projects can be added to the solution using the add module wizard:

    image

    Module is a basic organization unit in WCSF. A module actually contains several projects. The following picture shows the organization of the Contacts module:

    image

    As seen in the picture above, when we add the Contacts module, WCSF adds a folder Contacts in the web project and also add a Contacts library project. When we add a web page, WCSF adds a view interface and a presenter class into the Views folder of the module project. WCSF uses model-view-presenter (MVP) pattern so that the responsibility for each page is divided between a model, a view and a presenter. I have seen people talking about the complexity and the steep learning curve of WCSF. However, some knowledge of the lift cycle would make it much easier to understand.

    WCSF Lift Cycle

    Whether we create a new WCSF web site or modify an existing web site to work with WCSF, the first thing is that the the Web Application must inherit from Microsoft.Practices.CompositeWeb.WebClientApplication or its subclass. This can be done by setting the following in the global.asax page:

    <%@ Application Language="C#" Inherits="Microsoft.Practices.CompositeWeb.WebClientApplication" %>


    This will allow WCSF to participate in the application initialization process. Specifically, it will search the Web.Config in the application root directory and sub directories to find WCSF configuration. A typical WCSF configuration section looks like:

      <compositeWeb>
        <modules>
          <module name="Contacts" assemblyName="MVPWithCWABQuickStart.Contacts" virtualPath="~/Contacts">
          </module>
        </modules>
      </compositeWeb>

    The configuration inforamtion tells WCSF to load the module assembly and run the code in the ModuleInitializer class.

    A page or a web control that participate in the WCSF life cycle needs to inherit from the Microsoft.Practices.CompositeWeb.Web.UI.Page or the Microsoft.Practices.CompositeWeb.Web.UI.UserControl class. This allows the object builder to instantiate the presenter/controller objects and inject them into the view through dependency injection.

    The WCSF web page and the Model-View-Presenter pattern


    Whenever we add a page to the web project, WCSF will also create a view interface and a presenter. The web page inherits from the Microsoft.Practices.CompositeWeb.Web.UI.Page class and implements the view, as see in the following code snippets:

        public partial class ContactsList : Microsoft.Practices.CompositeWeb.Web.UI.Page, IContactsListView
        {
            private ContactsListPresenter _presenter;

            protected void Page_Load(object sender, EventArgs e)
            {

                if (!this.IsPostBack)
                {
                    this._presenter.OnViewInitialized();
                }
                this._presenter.OnViewLoaded();
            }

           
            [CreateNew]
            public ContactsListPresenter Presenter
            {
                set
                {
                    this._presenter = value;
                    if (value != null)
                    {
                        this._presenter.View = this;
                    }
                }
                get
                {
                    return this._presenter;
                }
            }
        }

    The inheritance from the Microsoft.Practices.CompositeWeb.Web.UI.Page class would allow the page to participate in the life cycle of a WCSF page which uses ObjectBuilder to inject dependent class when the page is constructed. The CreateNew atribute instructs ObjectBuilder to construct a new instance of ContactsListPresenter and assign it to the ContactList class. WCSF creates the view and presenter does not enforce how the model is created. There are two flavors of Model-View-Presenter (MVP) pattern used in WCSF: PassView and Supervising Controller.

    Ff709839.aa7a8362-061a-47fa-9666-0357c0d18505(en-us,PandP.10).png

    With Passive View, the Presenter is responsible for interacting with the business layer (the Model in this case). The view interface needs to expose every fields that the presenter would read and set. The web page would simply expose the control values as get and set properties. For example, the interface:

        public interface IContactsListView
        {
            int SelectedIndex { get; set;}
        }

    and the implementation:

            public int SelectedIndex
            {
                get { return CustomersGridView.SelectedIndex; }
                set { CustomersGridView.SelectedIndex = value; }
            }

    In the Supervising Controller, the Model is often a View Model that contains the data to be presented. The presenter would pass an instance of view model to the view and view is responsible for rendering the view model, often through a data binding mechanism. For example:

        public interface IContactDetailView
        {
            void ShowCustomer(Customer customer);
        }

    Comparing the two flavors, the Passive View requires a large view interface with many members. To add a new field, you would need to modify both the view interface and the view implementation. In contrast, with supervising controller, you would only need to modify the view model to add a new field. However, some data binding logic are handled in the view and is not testable.

    On Modulization


    In our project, we have a fairly complicated page that is furthered spitted into several user controls developed by several developers at the same time. Each user control is a view by itself and has its own presenter. However, these user controls often need to share the same time and communicate with each other. That is where the Controller comes into the picture. Fortunately, the WCSF project already contains a controller and the presenter template already contains the code to inject the controller; we only need to uncomment the code. For example:

        public class ContactsListPresenter : Presenter<IContactsListView>
        {
            IContactsController _controller;
            public ContactsListPresenter([CreateShared] IContactsController controller)
            {
                _controller = controller;
            }

            public IContactsController Controller
            {
                get { return _controller; }
            }
            …
        }

    In order to have all the user controls share the same instance of the controller, we have to change the dependency-injection attribute from CreateNew to CreateShared. This way, the entire request would share the same copy of the controller. The CreateShared attribute as well as the code that needs to be added to global.aspx can be downloaded from the WCSF contrib project.

    With all the user controls getting the same instance of the controller, the user controls can interact with each other by calling controller methods and subscribe to events fired by the controller.

    Unit Testing

    One major objective of WCSF is that the classes can be unit tested outside of a web server. This would requires creating mock view that implements the view interfaces to interact with presenters and controller. For this reason, one want to leave out as much as logic from the code behind as possible so they can be unit tested. In addition, the module project should be free of reference to request, session and other web server objects so that they can be tested outside a web server. The WCSF has StateValue<T> and StateDependency classes for injecting session value into the module classes. The WCSF contrib also has a QueryStringValue<T> class for injecting the query string parameters.

    Impression

    My impression is that WCSF works with an existing web form application very well. It can be used to split large project or complicated pages into smaller pieces to be worked simultaneously. We did not encounter any significant limitation with WCSF.

    The next question is whether we want to WCSF or ASP.NET MVC since this is a FAQ. The choice is really between WebForm and ASP.NET MVC. WCSF is just a way to make WebForm project more organized. I would say that WebForm is still the most productive framework (although it does not produce the most optimal HTML code). WebForm is a mature framework and has a abundant third party controls. If you have limited budget, performance is not major concern, or you use lots rich dhtml controls like treeview, WebForm is still the way to go. On the other hand, if you have a bigger budget, needs to product optimal Html code, or is concerned with the future growth of the project, and are comfortable to deal with the occasional situation of not able to find some server controls so that you have to use some JQuery client-side controls, then MVC is the way to go.

  • How to enable tracing in ASP Classic Compiler

    With the build 0.6.2, we added the option to enable tracing. The tracing can be enabled by setting the following in the global.asax.cs file:

    using Dlrsoft.Asp;
    AspHandlerConfiguration.Trace = true;

    Setting this option will tell the compiler to inject line number into the compiled code. If the compiled code throws any runtime error, the exception will contain the source file name and line number.

    If you would like to receive the complete trace history, you will have to configure a trace listener. VBScript.net compiler uses TraceSource “Dlrsoft.VBScript”. The following is an example configuration section in the web.config file:

    <system.diagnostics>
      <trace autoflush="true">
        <listeners>
        </listeners>
      </trace>
      <sources>
        <source name="Dlrsoft.VBScript"
          switchName="vbscriptSwitch"
          switchType="System.Diagnostics.SourceSwitch">
          <listeners>
          </listeners>
        </source>
      </sources>
      <switches>
        <add name="vbscriptSwitch" value="Verbose"/>
      </switches>
    </system.diagnostics>

    The above configuration will send the trace information to DefaultListener. You can see the trace output using DebugView. You might also route the trace output to ASP.NET tracing using the WebPageTraceListener. Please see this post for more information regarding tracing.

    Please note that enable tracing itself only adds a small overhead to the Asp Classic Compiler. However, some listeners can add a huge overhead.