Li Chen's Blog

  • Moving DLLs from bin to GAC in asp.net

    This must be a decade-old question, but surely come up to bite us again during the refactoring today. We decided to moved several shared DLLs from bin to GAC in several of our ASP.NET web sites. Here is what we found out:

    1. The code-behind files and the code in app_code directory failed to compile. The way to fix is add referenced assemblies to the compilation/assemblies section under system.web in web.config file. ASP.NET compiler will pickup DLLs in bin automatically but will not do so in GAC. We have to explicitly instruct it.
    2. If we update any DLL in GAC, we need to restart the application (e.g., using IISRESET) for APP.NET applications to pick up new versions of the DLL. ASP.NET shadows a copy of GAC DLLs in temp ASP.NET directory. While ASP.NET can detect DLL changes in the bin folder, it will not detect DLL changes in GAC until the application is restarted.
    3. Don’t even think of putting DLLs in both bin and GAC. There are well defined rules are which ones get actually used but doing so will only cause confusion. For more information, see http://stackoverflow.com/questions/981142/dll-in-both-the-bin-and-the-gac-which-one-gets-used.
  • Teaching high school kids web programming (Part II)

    A few months ago, I thought of teaching high school kids asp.net programming. I let the idea sit for a few months. Now that summer has started, I think about this again. The following communication with Microsoft Scott Hunter by InfoQ caught my attention:

    Web Matrix is the tool for Web Pages, their lightweight IDE to compete directly with PHP.

    Three ways to create web pages using ASP.NET and Visual Studio:

    • Web Pages: Extremely light weight, easy to build pages. No infrastructure needed, very much like PHP or classic ASP. Full control over the HTML being generated.
    • MVC: Same light-weight view engine as Web Pages, but backed by the full MVC framework. Full control over the HTML being generated. Upgrade cycle is approximately 1 year.
    • Web Forms: Component-based web development. Use when time to delivery is essential. Especially suited for internal development where full control over the look and feel isn’t essential. Upgrade cycle is tied to the core .NET Framework.

    The Scott went further to mention that “the Razor view model was designed for Web Pages first, then adopted by MVC 3.”

    So ASP.NET Web Pages is exactly what I needed. Although I have heard WebMatrix and Razor for a while (I even attempted to convert webform to Razor), I have failed to take WebMatrix seriously. We already got Visual Studio and the free Express edition. I always though Razor is just another view syntax to save a few key strokes until I realized that the Web Pages could be used without MVC. I found several tutorials on Web Pages:

    The ASP.NET Web Pages site

    The ASP.NET WebMatrix Tutorial (You my download the same material as a PDF eBook)

    Web Development 101 using WebMatrix

    Web Camp WebMatrix training kit

    These tutorial has everything that I need in my original goal without any more work me:

    • Be able to teach for just a few hours and get kids productive.
    • Close to HTML without the complication of OOP and black box (e.g., the complicated life cycle of WebForm).
    • Simple data access with SQL statements.

    Just a side note. Although the tutorials use WebMatrix, I could do everything in Visual Studio as well (though I did not try the Express edition). Just need to install ASP.NET MVC3 with latest Visual Studio tools. This will get Razor tools installed. Then create an empty website as the Razor tools are current not in the template for an empty web application.

  • Passing managed objects to unmanaged methods as method argument

    It is well documented how to expose a .net class as a COM object through the COM callable wrapper. However, it is not well documented how to pass a .net object to a COM method in an argument and have the COM method treat the .net object as COM. It turns out all we need to do is to add the [ComVisible(true)] to the classes that we need to pass to COM method; runtime would recognize that we are passing the object to COM and generate the COM callable wrapper automatically.

    However, there are some impedance mismatches between COM and .NET. For example, .NET supports method overloading while COM does not. COM objects often uses optional arguments so that the client can pass variable number of arguments to the server. I used the following pattern to expose the Assert object to unmanaged VBScript engine in my VBScriptTest project in ASP Classic Compiler:

            [ComVisible(false)]
            public void AreEqual(object expected, object actual)
            {
                Assert.AreEqual(expected, actual);
            }
            [ComVisible(false)]
            public void AreEqual(object expected, object actual, string message)
            {
                Assert.AreEqual(expected, actual, message);
            }
            [ComVisible(true)]
            public void AreEqual(object expected, object actual, [Optional]object message)
            {
                if (message == null || message == System.Type.Missing)
                    AreEqual(expected, actual);
                else
                    AreEqual(expected, actual, message.ToString());
            }
    

    Note that I marked the first two overloaded methods with [ComVisible(false)] so that they are only visible to other .net objects. Next, I created a COM callable method with an optional parameter. The optional parameter must have the object type; runtime will supply the System.Type.Missing object if a parameter is not supplied by the called. So in the body of the method, I just need to check whether the parameter equals to System.Type.Missing to determine whether the parameter is passed.

  • /Platform:AnyCPU, /Platform:x64, /Platform:x86, what do they mean

    When we build a .net solution, we often see the Platform choice in the configuration manager:

    image

    Besides AnyCPU, other choices are x86 ,x64, and Itanium. What do they mean? According to MSDN, “Anycpu” compiles the assembly to run on any platform while the other 3 choices compiles the assembly for 32 bit, 64 bit x64 and 64bit Itanium respectively.

    On a 64-bit Windows operating system:

    • Assemblies compiled with /platform:x86 will execute on the 32 bit CLR running under WOW64.

    • Executables compiled with the /platform:anycpu will execute on the 64 bit CLR.

    • DLLs compiled with the /platform:anycpu will execute on the same CLR as the process into which it is being loaded.

    If a .net application uses any 32 bit ActiveX component, it will not be able to load the component in-process. We have two choices:

    1. Host the 32 bit component in an external process, such as COM+ Server Application, or
    2. Run the .NET application as a 32 bit application.

    The VBScriptTest project in ASP Classic Compiler contains an unmanaged test. It hosts the msscript.ocx so that I can compare my .net implementation of VBScript against the original VBScript engine from Microsoft. In order to use the 32 bit msscript.ocx, I need to run my unit test in a 32 bit process. NUnit has a 32 bit version of the test runner call NUnit-x86.exe. To use the 32 bit runner, I registered new shell extension as shown below so that I can use the “Run 32 bit NUnit” context menu to invoke the 32 bit NUnit test:

    image

    Lastly, how to run ASP.NET in 32 bit? It turned out that this is controlled by the Application Pool. If I set the “Enabled 32 bit Application” to true in the Advance Property Setting of the application pool, the ASP.NET application will run in 32 bit.

    image

  • Build a very green Windows Server

    My old server consumes about 80W. Given my top tier electricity cost of $0.24/KWh, it costs me about $14 in electricity each month, and generates considerable noise and heat. Recently, I set out to build a greener server. I bought an Intel Atom Dual-Core D525MW Fan-less Motherboard for $80 and a Apex MI-100 mITX case for $40. I also I bough an Kingston 64GB SSD for $75 after rebate. I used 2 x 2GB DDR3 SODIMM RAM and a Toshiba 250GB notebook drive scratched from my recent laptop upgrade. So my total out-of-pocket expense is just under $200 before tax. If I include the cost of retired parts, the hardware cost is about $300. I cloned my Windows 2003 Server OS from my old server into my new server. Although Intel does not supports server OS from desktop boards, I was actually able to install all the necessary drivers from the Intel CD despite the setup program reported installation failure on 3 out of 4 drivers. The new server is barely audible; it is quieter than a outlet timer. Like any machine powered by an SSD drive, it boots up in seconds.

    2011 MVP Summit 016 (600x800)

    So how much power does it consume? My Kill-A-Watt meter tells me that in consumes just under 30 watt at idle. To put that in perspective, my previous Dish Network Receiver and my current Time Warner HD Receiver each consumes about 20 watt at idle. It is quite adequate as my server.

    2011 MVP Summit 017 (480x640)AtomD525

  • ASP Classic Compiler: the unit testing framework is released

    In my previous post, I stressed the importance to have a unit testing framework to move forward with this project. I was facing the decision whether to use NUnit or MSTest. After some thoughts, I came to the conclusion that the choice of unit testing framework is not critical, at least for now. For a language project, unit testing usually falls into two categories: the testing of a parser and the testing of generated code. For parser testing, most of work lies in comparing AST generated by the parser with the expected AST. Paul Vick has an excellent framework in his VBParser work. For testing of the generated code, it is best to have a unit testing framework that is self-contained in the target language so that is can most accurately test the semantics of the language. For example, Javascript has the QUnit framework and ASP Classic has the ASPUnit framework.

    So I went ahead to release my own unit testing framework for VBScript. I created an interface called IAssert that has the following methods:

            void AreEqual(object expected, object actual);

            void AreEqual(object expected, object actual, string message);

            void AreNotEqual(object notExpected, object actual);

            void AreNotEqual(object notExpected, object actual, string message);

            void Fail();

            void Fail(string message);

            void IsFalse(bool condition);

            void IsFalse(bool condition, string message);

            void IsTrue(bool condition);

            void IsTrue(bool condition, string message);

    These are minimum set of method often found in most of unit testing frameworks. We can always add more when needed. Note that I did not have IsEmpty or IsNothing methods. That is because I believe we should use the language built-in method to best reflect the language semantics. For example, instead of having an IsEmpty method in the testing framework, we should use IsTrue(IsEmpty(myVar)) where we are using the VBScript built-in function.

    In environments that we have control over the host, the host will supply an Assert object that can route the testing results to one of the existing unit testing framework, such as NUnit, so that we can reuse the test runners and report functionalities. In the environments that we do not have control of the host, we can supply an Assert class in VBScript itself, much like what ASPUnit does.

    If you look at my VBScriptTest project, you will notice that it uses NUnit framework. It has a single NUnit test case that walks the entire hierarchy under the VBScripts folder. When we need to write a new test case, we just simply add a .vbs file under the VBScripts folder. The following is an example VBScript unit test case:

    dim a
    Assert.IsTrue(IsEmpty(a), "Unassigned variable must be empty")

    Because I have use a single NUnit test case to run all the VBScripts, the message parameter is an important parameter to distinguish the test case in the situation of failed test case.

  • ASP Classic Compiler: the next step

    I opened the source code for my ASP Classic Compiler 2 days ago. As this project was started as a research project, proof of concepts has been a major goal. I have cut corners whenever possible to bring out features fast. Going forward, there are many things that need to be tighten up. The following are my top priorities:

    1. Unit testing: You eager downloaders may have noticed the my project is notoriously missing unit tests. I intentionally took out my unit tests when I upload because my previous unit tests were not well organized. I want to give us chance of a fresh start. Since we will have refactoring and re-architecture of the code generator, unit testing is going to carry this project. Like many open source projects, NUnit or MSTest is a decision to make. I have created this thread in my forum to solicit ideas. I don’t quite need StackOverflow style discussions as there are already plenty. But if you look at recent high profile switches in either directions, you would know this is not an easy decision.
    2. Making it easier for people diagnose problems. A debugger is not going to happen easily, as I have already tried twice. But with source code, it is still possible for people to diagnose problems. This will help reducing the frustration level and getting bug reported and fixed.
    3. VBScript 5.0 support. This is my real top goal since many people requested it, but I could not get there without 1 and 2. I want to take over the memory management since I have already pushed DLR to the limit. Controlling the memory management will open up the possibility for debugging. Details is going to be a blog by itself.
    4. Performance improvement when calling CLR static methods. The TypeModel used in VBScript.NET does not take advantage of call-site caching and is hence very slow. Fortunately, this can be corrected fairly easily.
    5. Optimize for multiple string concatenations. This has been a habit in many ASP projects. I can discover this in code analysis and generate the code behind the scene using StringBuilder. This is a pretty fun research project and it is not too hard.
    6. Type checking in many places can still be optimized for callsite-caching.
    7. Rewrite of the parser. Currently, my VBScript parser is modified from Paul Vick’s VBParser which was written in VB.NET. I have some concern on VB.NET’s timely availability in new platforms (remember Windows Phone 7?). However, since my code generator is tightly coupled to the abstract syntax tree (AST) in the parser project, this is going to be a messy work.