Navigation

Search

Categories

On this page

ASP.NET IHttpAsyncHandler vs IHttpHandler
Microsoft Azure Critique/Review
Why Managed Windows Services Hog Memory and Eventually Crash
Thousands Separator When Formatting Numeric String in .NET (C#, VB.NET) Programming
Make Your ASP.NET Application FIPS Compliant for US Government Use
Dealing with Missing Dataset Editor in Visual Studio 2008
Download WebService Studio 2.0
VS 2008: Windows SDK 6.0 Needed for WCF "Service Configuration Editor" Utility
How Windows Performance Counters of "Average" Types Linked to Their Bases
Open-Source And Me
Microsoft Ajax 1.0 Extensions: Converting Existing ASP.NET Application Into AJAX-Enabled One
Microsoft "Acropolis" six years too late. I liked CCmdTarget of MFC back in nineties.
Creating Web-Based MP3 Player using ASP.NET 2.0, UltiDev Cassini Web Server and Macromedia Flash Player
Problem with Macromedia (Adobe) Flash Object on the ASP.NET Page Served by Visual Studio 2005 WebDev.WebServer2.exe
.NET API for Programmatic MP3 Tag (ID3v1 and ID3v2) Access and Modifications
Software platform evolution: from desktop OSes to World Wide Web to UltiDev HttpVPN
MSI-based setup packages custom actions made in Visual Studio may not work correctly in upgrade mode
Running MSI is not the same as running Setup.exe on Vista with UAC turned on.

Archive

Blogroll

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

RSS 2.0 | Atom 1.0 | CDF

Send mail to the author(s) E-mail

Total Posts: 53
This Year: 20
This Month: 2
This Week: 0
Comments: 8

Sign In
Pick a theme:

 Monday, November 10, 2008
Monday, November 10, 2008 3:52:23 PM (Eastern Standard Time, UTC-05:00) (  |  |  |  )

Since I use ASP.NET Http handlers quite often, I decided to figure out what advantages IHttpAsyncHandler has compared with IHttpHandler. As I looked at many people's claim that IHttpAsyncHandler somehow magically improves performance by shifting process handling on to another thread, I realized that MSDN documentation of IHttpAsyncHandler is laking in a fundamental way: it fails to mention that simply moving request rendering onto another thread does not yield any benefits. The doc fails even to mention the goal of IHttpAsyncHandler is pretty much just to manage ASP.NET request thread pool more efficiently. This means that your application using synchronous IHttpHandler will suffer performance penalty only when your application runs out of threads dedicated by ASP.NET to handling requests. This means that, first, it makes sense to consider switching to IHttpAsyncHandler only if your requests are high-latency. However, even then switching to IHttpAsyncHandler may not provide any performance gain unless bulk of requests processing (or waiting for conditions allowing processing to begin) occur on a thread other than one coming from ASP.NET thread pool!! Please note that creating your own thread does not make anything any more efficient, because you can achieve same net result by tweaking ASP.NET thread pool size in the web.config. In most cases this means that unless your BeginProcessRequest() implementation starts an async I/O operation that takes async callback as a parameter, the whole IHttpAsyncHandler business is a waste of time. Since such I/O will create its own thread anyway, the benefit comes out of using that IO thread to process the request.

The rule of thumb should be this: if most of your request processing is done by a callback invoked in response to an I/O completion, and therefore on the IO thread, then usage of IHttpAsyncHandler is justified.

Comments [0] | | # 
 Friday, November 07, 2008
Friday, November 07, 2008 9:53:48 AM (Eastern Standard Time, UTC-05:00) (  |  |  |  )

Microsoft marketing folks are incorrigible. When explaining new technology they invariably fail to make anything any more clear. Case in point: Microsoft Azure. Parsing through the Azure site left an impression that MS don't really want anyone to find out what in the world they are really doing.

For those who don't have time to filter through MS marketing noise, consider reading this very concise, pretty funny even if somewhat crude-worded Windows Azure review:
http://www.theregister.co.uk/2008/11/03/dziuba_azure/print.html

Comments [0] | | # 
 Wednesday, October 29, 2008
Wednesday, October 29, 2008 9:52:59 PM (Eastern Standard Time, UTC-05:00) (  |  |  |  )

It's very easy to write a windows service using C# or VB.NET. Easy to write, easy to install, but for a price.

It's an often overlooked fact, but in .NET runtime, Garbage Collector does not merge together freed memory chunks, if they are larger than 85K. What does it mean? It means that if your managed windows service allocates and frees buffers larger than 85K on a continuous basis, your service will crash because it will eventually run of memory due to Large Object Heap (LOH) fragmentation. Again, it will only happen if your managed windows service allocates objects of 84,000+ (give or take) byte, but IT WILL HAPPEN!

There are workarounds, somewhat expensive, like wrapping your service logic in COM+ server-activated process, which can be set up to recycle - just like IIS AppPools are recycled. Or one could create a proprietary memory manager with a pool of large buffers, making of which, of course, would be kind of ironic since the whole point of having garbage-collected memory manager was to eliminate hassles of memory management.

Anyway, the purpose of this post is to raise awareness among fellow windows service developers. If your service is high-throughput, high memory usage, it will go down in flames even if your code is perfect. The choices are: a) ensure all your memory allocations do not take more than 84K, b) implement your own memory manager, or c) implement worker process recycling.

Good luck to all of us.

Comments [0] | | # 
 Saturday, July 26, 2008
Saturday, July 26, 2008 10:18:35 AM (Eastern Standard Time, UTC-05:00) (  |  |  |  )

It's much easier to read large numbers when thousands are separated by commas. But I can never remember how the numeric format with thousands comma-separated is defined for .NET String.Format() method and for the databinding. So more as a note to self, here it is:

string output = string.Format("{0:#,#}", 123456789); // Will produce 123,456,789

The same goes for data binding data sources to data controls like DataGridView. Specify format as "{0:#,#}".

Comments [0] | | # 
 Wednesday, July 23, 2008
Wednesday, July 23, 2008 1:23:18 PM (Eastern Standard Time, UTC-05:00) (  |  |  )

If your ASP.NET 1.1 or 2.0 application throws "This implementation is not part of the Windows Platform FIPS validated cryptographic algorithms" exception, the easiest way to fix is to add 
      <machineKey validationKey="AutoGenerate,IsolateApps" decryptionKey="AutoGenerate,IsolateApps" validation="3DES" decryption="3DES"/>
line to the <system.web> section of the web.config file of your application.

FIPS compliance is required for software installed on US government computers. The compliance requirement can be turned on and off.

Source: http://support.microsoft.com/kb/911722

Comments [0] | | # 
 Friday, July 04, 2008
Friday, July 04, 2008 6:25:39 PM (Eastern Standard Time, UTC-05:00) (  |  )

After I have upgraded the motherboard on my desktop, a few things got messed up, the most annoying of which was that Visual Studio 2008 has lost its XSD/Dataset editor. Opening a data set resulted in opening it as a text or XML, and when I right-clicked the XSD file and selected "Open With..." from the menu, the XSD editor was not there. Repairing and completely uninstalling and reinstalling VS 2008 did not help. After searching the web I found that some people have the same problem, but I found no solution for Visual Studio 2008. The solution that worked for me was described for the similar problem with Visual Studio 2005. I ran “devenv /resetsettings” and it didn't help. Then I ran “devenv /setup” and hallelujah: XSDs are opening again in the Design mode! To launch devenv you will need to start VS 2008 command prompt first.

Comments [0] | | # 
 Monday, May 19, 2008
Monday, May 19, 2008 9:32:03 AM (Eastern Standard Time, UTC-05:00) (  |  |  )

WebService Studio 2.0 (a.k.a. Web Service Studio) is a quick & dirty web service client tool that can import your web service's WSDL and allow you to call web service's methods without having to create your own test client.

WebService Studio used to be hosted on Microsoft's GotDotNet web site, but ever since GotDotNet was replaced by Codeplex, Web Service Studio was nowhere to be found. Fortunately, some kind stranger made WSS available for download at his blog: http://mattharrah.com/blog/web-tools/net-web-service-studio-20/.

Update: BTW, if you are planning to use WebService Studio to test WCF web services, you will need to configure your web service to use basicHttpBinding instead of wsHttpBinding.

Comments [0] | | # 
 Thursday, May 15, 2008
Thursday, May 15, 2008 3:53:38 PM (Eastern Standard Time, UTC-05:00) (  |  |  |  )

After installing Visual Studio 2008 on a new machine and starting playing with a simple Windows Communication Foundation project, I attempted to change service's WCF settings using WCF Service Configuration Editor utility (SvcConfigEditor.exe). However, I got the "Windows SDK is not installed correctly" error. "Internets" were surprisingly mum on the subject, so I had to figure out the solution myself.

To fix the problem, I had to install Windows SDK 6.0 manually. After I did that, the problem went away. Just quit Visual Studio 2008 before installing Windows SDK.

Update: Even after reinstalling Windows SDK, first time right-clicking on the web.config in the Visual Studio '08 Solution Explorer does not bring "Edit WCF Configuration" item to the menu. However, after I did Tools | "WCF Service Configuration Editor", "Edit WCF Configuration" item started showing up upon right-clicking the .config file.

Comments [0] | | # 
 Thursday, March 20, 2008
Thursday, March 20, 2008 5:04:21 PM (Eastern Standard Time, UTC-05:00) (  |  |  |  )

Some time ago I added performance counters to the application I was working on, and for some inexplicable reason all counters of "Average" type, like AverageCount64 or AverageTimer32, didn't work at all, always having 0 value. Then I had no time to find out why it was not working, but today I did. As you may know, "Average" counters are made of two distinct counters: the base counter and the average counter itself. The mystery was that by looking at all the samples returned by Google, it was unclear how the Base and the Average itself are linked together. It looked like you create the Base and the Average, add them to the collection and somehow magically Windows figures they need to be linked together when averages are calculated. After some research it looks like the two are linked by counter name! It appears that base's name should be the name of real counter, plus word " base". For example, when you define your counter category that has average performance counter, you do something like this:

   counters.Add(
new CounterCreationData("whatever", "whatever desc", PerformanceCounterType.AverageCount64));
   counters.Add(new CounterCreationData("whatever base", "whatever base desc", PerformanceCounterType.AverageBase));

To my surprise, changing the "whatever basevalue of the counter name in both CounterCreationData and PerformanceCounter to something like "whatever base1" breaks the perf counter! It looks like there is a naming convention requiring that AverageBase proformance counter has the CounterName property value on both CounterCreationData and PerformanceCounter to be counter name plus " base", but I never saw this mentioned anywhere - neither by MSDN, nor by Codeproject articles. So, since average perf counters always come in pairs, linked by name, these helpers should make creating average perf counters simpler (uinsg C#/.NET):

        private static void AddAverageCounterDefinition(CounterCreationDataCollection counters,

                        string counterName, string counterDescription, PerformanceCounterType averageType)

        {

            counters.Add(new CounterCreationData(counterName, counterDescription, averageType));

            counters.Add(new CounterCreationData(counterName + " base", string.Empty, PerformanceCounterType.AverageBase));

        }

 

        public class AveragePerfCounter

        {

            private PerformanceCounter averageCounter;

            private PerformanceCounter averageCounterBase;

 

            public AveragePerfCounter(string categoryName, string counterName)

            {

                this.averageCounter = new PerformanceCounter(categoryName, counterName, false);

                this.averageCounterBase = new PerformanceCounter(categoryName, counterName + " base", false);

            }

 

            public void IncrementBy(long val)

            {

                this.averageCounter.IncrementBy(val);

                this.averageCounterBase.Increment();

            }

        }

 

After this, when creating performance counter definition, you could use following code instead of the one shown by the very first snippet:
      AddAverageCounterDefinition(counters, "whatever", "whatever desc", PerformanceCounterType.AverageCount64);
It will add " base" to the name of the sidekick automatically.

And to create corresponding performance counter, you now can do this:
      AveragePerfCounter avgCount = new AveragePerfCounter("MyCategory", "whatever");
     
avgCount.IncrementBy(new Random().Next(100));

 

Comments [0] | | # 
 Wednesday, August 01, 2007
Wednesday, August 01, 2007 10:51:18 AM (Eastern Standard Time, UTC-05:00) (  |  |  |  )

CodePlex.com - a relatively new open-source collaboration platform from Microsoft that came to replace old and cranky GotDotNet - has impressed me quite a lot. Of course it closely resembles SourceForge.net, with the main difference of CodePlex being underpinned by Team Foundation Server (TFS) for source control and issue tracking functionality.

People often don't realize that TFS client that integrates into Visual Studio 2005 can be downloaded and is completely free.

I currently host a couple of projects on Codeplex:

  • MS AJAX 1.0 Setup Project Prerequisite for Visual Studio 2005.
    It makes MS AJAX redistributable by including it into the Setup.exe bootstrapper prerequisite manifest. The prerequisite integrates nicely with Visual Studio 2005.

  • Simple ASP.NET 2.0/C# MP3 Player.
    This application demonstrates a possibility of building a web application for home users. It includes redistributable UltiDev Cassini Web Server for ASP.NET 2.0 to not make the application dependent on the presence of IIS on users machines. The app is AJAXed to minimize music interruptions and uses Flash player to playback MP3 to avoid dependency on any particular media player. 
Comments [0] | | # 
 Friday, June 22, 2007
Friday, June 22, 2007 12:01:40 PM (Eastern Standard Time, UTC-05:00) (  |  |  )

To AJAX-enable your existing ASP.NET 2.0 application follow this video. It takes only a few minutes and essentially makes you create a dummy new Ajax-enabled ASP.NET application and then copy & paste relevant pieces of its web.config file into your application's web.config.

If you are planning to use Ajax Control Toolkit, then instead of creating dummy project from the "ASP.NET AJAX-Enabled Web Site" Visual Studio project template, create the dummy project using "AJAX Control Toolkit Web Site" template. Its web.config has additional entry in the <controls> section of the web.config that will be necessary for your application.

Comments [0] | | # 
 Tuesday, June 19, 2007
Tuesday, June 19, 2007 9:42:13 AM (Eastern Standard Time, UTC-05:00) (  |  |  |  )

Microsoft is showing off its new Acropolis framework for .NET. It seems to be a little more than good old CCmdTarget of late MFC. 

Back in 2001 when I was making a transition from C++/MFC to C#/.NET two things I missed the most were C++ templates and CCmdTarget/Doc/View architecture of MFC-based Windows UI. I could not believe Microsoft didn't port CCmdTarget at the time and naturally wrote my own. But pretty soon it was obvious that with C# and Visual Studio .NET writing ASP.NET web applications was easier than making Windows UI apps, and people wanted web UI more than windows UI.

Combine dwindling demand for Windows UI with inferior development tools and you end up in the situation where software architects don't even debate whether their next enterprise application should have Windows UI or web UI. It's assumed and understood that it will be a web-based application. If you think an application needs to have Windows UI - you will face an uphill battle convincing other project stakeholders it's the right way to go.

Simply put, Windows UI is so out, and web UI is so in that incremental improvements in Windows UI world like WPF and Acropolis is too little and way too late to save the day. We've got AJAX, thank you very much. In my arrogant opinion enterprise apps will not go back into Windows UI world. The last bastion of Windows UI applications is SOHO market, but that is about to change with HttpVPN making it possible to make easily redistributable web applications for consumers and small businesses. Once that happens, Windows UI will become just gaming and other graphics-heavy applications platform.

Comments [0] | | # 
 Monday, March 05, 2007
Monday, March 05, 2007 6:30:06 PM (Eastern Standard Time, UTC-05:00) (  |  |  |  )
Summary

UPDATE: This sample is an open-source project now.

This article describes how to build a redistributable ASP.NET application that allows users browse remote server's file system and pick folders with MP3 files to be played by embedded Macromedia Flash-based MP3 player.


Article Sources

Download article's C# source in a form of Visual Studio 2005 Solution comprising ASP.NET application and a Setup Project. Unzip the archive to "C:\".


End Result

UltiDevMP3Player-2-Thumbnail.PNG  

After building the project you will have an MSI-based setup package that can be installed on virtually any Windows-based PC. Installed application will be accessible from inside the LAN as an intranet application without having to install IIS.


Prerequisites

- Visual Studio 2005.
- UltiDev Cassini Web Server for ASP.NET 2.0. UltiDev Cassini is packaged together with the application into the Setup.exe so that the final application would not depend on IIS being present on target system.


Let's Begin (Getting Ducks in a Row)

A few weeks ago I stumbled upon a great piece of free software:Flash-based XSPF-compatible MP3 player. When embedded on a page, it can take playlist over HTTP and play it. Second nice thing was that XSPF play list format has XSD schema available. .NET Framework xsd.exe utility allows easy conversion of XSD schemas into C# or VB.NET classes incapsulating the structure of the data defined by the XSD, as well as implementing XML serialization to and from XML files conforming to the schema. So I had an XSPF-compatible MP3 player and a free code generating XSPF-compatible XML. That meant I could easily create XSPF-compatible playlists on a fly. Only if I had free ID3 tag (MP3 file metadata) access API...

Finding ID3v2 library for .NET was harder than I expected. However search was ultimately successful. The UltraID3Lib ended up being just what I needed. It's a nice library; may be just be a bit over the top object-oriented.

Final piece is UltiDev Cassini Web Server for ASP.NET 2.0. It's necessary because first, it can be packaged and shipped along with any ASP.NET application eliminating requirement for IIS. Second, unlike IIS UltiDev Cassini service works under "Local System" account, which enables access to any local file and folder on the server. One thing to note, while this is quite convenient to have a web server running under powerful account, it may pose a risk if the application is exposed on the web. It's best to work with the application inside protected local area network.

After you have downloaded the solution, unzip it on C:\. It will create "C:\UltiDevMusicPlayerSample" folder. If you want to put it in some other folder - you can do that too - simply adjust your project debugging settings later to point to the correct application folder (see below).


Application Flow

- Application has a single page (Default.aspx) containing the player control and file a system browser (Controls/PlayerControl.ascx and Controls/PlayerControl.ascx.cs).
- After user selected a folder with MP3 files, file system browser tree gets hidden and player control is re-rendered to point to the dynamically-generated playlist representing selected folder.
- Player control requests dynamic playlist and custom IHttpHandler (AppCode/PlaylistClass.cs and AppCode/xspf.cs) serves XSPF-encoded playlist containing songs in the selected folder. Playlist contains song information retrieved from songs' ID3v2 and ID3v1 MP3 tags.
- Player plays songs one by one: requesting each one from the custom IHttpHandler (Handlers/Song.ashx) serving songs from local file system. After song started playing player also requests song album artwork (cover art) from custom IHttpHandler (Handlers/CoverArt.ashx) which serves image extracted from song's ID3v2 tag.

Debugging

I had troubles getting Visual Studio 2005 internal web server to serve Flash component. I switched to UltiDev Cassini for debugging and that has solved the problem. Debugging with UltiDev Cassini is probably a good idea anyway since the application is eventually going to run under UltiDev Cassini.

To switch to UltiDev Cassini, bring up ASP.NET application's properties, select Start Options of the left, and check "Start External Program" radio-button. Enter "C:\Program Files\UltiDev\Cassini Web Server for ASP.NET 2.0\UltiDevCassinWebServer2.exe" as the program to be used for debugging, and specify "/run c:\UltiDevMusicPlayerSample\WebApp Default.aspx 4125" (no quotes) as command line arguments. If you have unzipped solution to a folder other than "C:\", then you will need to modify c:\UltiDevMusicPlayerSample\WebApp part of the command line arguments to point to the actual application location.
VS2005DebugSettingsForMP3App.PNG


Setup Project

Unlike regular ASP.NET application, this application is using regular (non-web) setup project for installer implementation. The reason for that is the Visual Studio web setup project is actually IIS setup project. Since we are using UltiDev Cassini instead of IIS, regular setup project is required instead.

Setup project packs UltiDev Cassini into Setup.exe bootstrapper and ensures application is registered with UltiDev Cassini during installation process and gets unregistered during uninstallation.

Creating a setup project for ASP.NET application bundled with UltiDev Cassini is not complex, but if you need step-by-step guide, please refer to this walk-through.

IMPORTANT: When installing the application, don't just click the .MSI file. You will need to run Setup.exe to ensure UltiDev Cassini web server gets installed on target system. This is especially true on Vista, where clicking .MSI and running Setup.exe are not nearly as functionally close as it used to be on Windows XP.

Build & Enjoy!

Comments [0] | | # 
Monday, March 05, 2007 4:22:37 PM (Eastern Standard Time, UTC-05:00) (  |  |  |  |  )

Recently I've been working on the small ASP.NET 2.0 app that has a page containing Macromedia (now Adobe) Flash object. When I tried debugging it with Visual Studio 2005 and its internal web server, the Flash piece has never been loaded by Internet Explorer - I am not even sure whether it was the Flash player that failed to load or the .SWF file. I wonder if anyone else had this issue. I could not check which component was not loaded because WebDev.WebServer2.exe serves only local applications, and I could not use an http tracer to see which request gets stuck.

I worked around the issue by switching to our own UltiDev Cassini for ASP.NET 2.0 for application debugging. It served all the bits and pieces required by Flash without a hitch.

Comments [0] | | # 
 Tuesday, February 27, 2007
Tuesday, February 27, 2007 11:37:38 PM (Eastern Standard Time, UTC-05:00) (  |  |  |  )

In attempt to create a less dry than your usual "Hello World" ASP.NET application to showcase UltiDev Cassini Web Server, I decided to write a simple web-based MP3 player application using Maсromedia (now Adobe) Flash. I was very surprised by how long and frustrating was my search for a free .NET-based API allowing programmatic access to ID3 tags in MP3 files from C# and VB.NET. I started working with something I found on Codeproject.com, but that piece turned out to be buggy beyond any degree of practicality. My second sweep across Internet yielded a much better (if only somewhat over-engineered) solution - the UltraID3Lib. Its UltraID3 class is the starting point of the journey. The library worked out for me very well. Thumbs up.

Comments [0] | | # 
 Sunday, February 11, 2007
Sunday, February 11, 2007 10:27:32 PM (Eastern Standard Time, UTC-05:00) (  |  |  |  )

Think what would happen if Microsoft was giving away Windows for free to everyone, and would also be giving away Visual Studio to developers, but taking %% of every sale of every program ever made for MS Windows. Think of how much more money would they would have made? Could Bill Gates have become  a first trillionaire?

 

First of all, no worries, I am not a nut who writes another OS. Creating a new operating system is WAY too complicated, costly and most importantly financially risky: OSes are commodity - it's impossible to change the world by creating another OS now.  Instead, I am creating a new platform. What is platform? To give a definition, platform is an operating environment for programs, and a user interface conduit for users. To give a few examples: Internet is platform: back-end web server is an operating environment for programs and browser is a conduit for the UI; every operating system is a platform: Windows, Linux, MacOS – their APIs and drivers form an operating environment and OS desktop and windows is a UI conduit; web browser is a platform too, albeit a limited one – it can run client scripts and therefore it’s an operating environment and a UI conduit at the same time. You get the idea…

 

Platforms differ in reach and complexity. Operating systems make a somewhat mediocre platform: they have limited reach – contained by the hardware they designed for, by how incredibly expensive it is to make an OS, and by how hard it's to learn to develop applications for a new OS. Adoption threshold for a new OS is very high. Web, on the other hand, is a very good platform: HTTP protocol is insanely simple, web development is relative simple and mastered by ever-growing legions of developers, web is not constrained by hardware, and finally web has a virtually unlimited reach. Curiously, web as a platform is built on top of other platforms - underlying disparate OSes running web server back-end software and user browsers. it’s a platform layered on top of other platforms – OSes.

 

The drawbacks of the Web as a platform include:

  1. Deploying and operating web apps is complex and costly. It is very hard to make an application accessible on the web: all the routers, firewalls, networking, DNS servers, domain names leases, IP addresses -  everything involved in deployment of a web application is much more complex from user’s standpoint compared to regular program with a "pop-in a CD and have it installed" type of deployment;

  2. Web applications are hard to market. From developers’ perspective business models for selling web app is limited to big-ticket sales to businesses who have budget and skills necessary to run web-facing infrastructure.

Now, imagine World Wide Web with above-mentioned problems removed. That is what I am doing: a new web-based platform that has user reach as wide as current Internet, but removes application deployment and marketing hurdles that are limiting web application usage right now. That’s a unique innovation right there. “But hey, there’s more!” Another unique innovation is the business model: I am not going to sell this platform to users, or development tools to developers. All will get it for free. The catch? All software that uses our platform can only be sold and bought using channels belonging and controlled by UltiDev, and like eBay we are going to take %% of every application sale.

 

You may have some concerns, like will developers find this new platform attractive enough to spend effort learning it and making programs for it? The answer is no, they won’t. Because they won’t need to. The beauty of it is that application developers can take their existing skills and even their already-built applications and simply package them together with our new platform components and ship it to users. Every member of millions-strong army of web developers worldwide is ready to take advantage of this new platform.

You may also wonder how complex is this new platform? Will it take billions of dollars an decades to create it? Well, it’s complex enough to take two years to develop, but the good news is that it’s virtually finished and working pre-alpha releases are deployed. 

Small detail: the platform described above is called HttpVPN™ and some additional technical information is available at http://ultidev.com/Products/httpVPN/.

Comments [0] | | # 
 Thursday, February 08, 2007
Thursday, February 08, 2007 11:42:07 PM (Eastern Standard Time, UTC-05:00) (  |  |  |  )

All! If you use Visual Studio 2003 or 2005 to create MSI-based setup packages, here's a good one for you: if your installation uses Uninstall and Install/Commit custom actions implemented as an installer class - you are in trouble. In the process of upgrading your product MSIEXEC.exe first loads an assembly with Uninstall custom action implementation - to complete previous version uninstallation. After that it tries to load installer class of the new version to do Install and/or Commit custom actions of the new version. At this point things can get really bad. If your custom action assembly is not signed/strongly named (and in my experience sometimes even if it is signed) MSIEXEC.EXE will fail to load custom action assembly from the new version and will run Install/Commit custom steps from the old one. This means that if you added new code to your Install/Commit steps it simply won't be executed during upgrade. Even worse: Install/Commit custom actions of the old version will run instead of the new one!

This happens due to completely bizarre, to put it mildly, logic of .NET Assembly.LoadFrom() method. .NET Framework has a rule that after assembly is loaded it can't be unloaded unless it was loaded into a separate AppDomain: appdomains can be unloaded and assemblies can't. Two assemblies may end up looking the same to LoadFrom() if they have the same name even if they are located in different folders or have different versions. So what happens here is this: after MSIEXEC.exe loaded assembly named 'X' to do Uninstall custom step, the subsequent attempt to load assembly named also 'X' from another folder to do Install/Commit step does not happen. But get this: one would expect that if you asked LoadFrom() to load assembly 'X' from folder 'Y' it should either load it or tell you it can't. Instead due to some truly twisted logic, LoadFrom() won't fail if it can't load new 'X' assembly - it will simply return the reference to the one that is already loaded. So much for solving DLL hell problem!

Microsoft knows about the problem since 2004
http://support.microsoft.com/kb/555184/

It didn't, however, fix it yet:
http://support.microsoft.com/kb/906766

They recommend giving unique names to custom action assemblies for each new release. Alternatively they say signing an assembly will make problem go away. I tried signing and in my small test project it made problem go away, but not in the "real" one. I am stuck with having to rename custom action installer assemblies for each release. All Microsoft needed to do is this: force installer to create new appdomain and load old version's Uninstall custom steps assembly there and let it run. After it's done, unload the appdomain and create the new one where you load new version's custom action assembly with Install step implementation. That would make it unnecessary to give assemblies unique names - strong or physical. My understanding is that Visual Studio adds a small shim DLL to the MSI package that loads .NET installer classes from the custom action assemblies. This means they don't even need to wait for another MSI API release to fix it - every new Visual Studio or a even a Service Pack for Visual Studio could have fixed the issue that is still with us more than three years later.

Comments [2] | | # 
 Tuesday, February 06, 2007
Tuesday, February 06, 2007 12:33:43 AM (Eastern Standard Time, UTC-05:00) (  |  |  |  )

In Windows XP one could just double-click an .MSI (Windows Installer) file to start package installation: MSIEXEC.exe is associated with the .MSI extension and if user had administrator rights installation would go forward. Clicking .MSI file was functionally identical to running Setup.exe bootstrapper, provided Setup.exe didn't have additional functions other than starting the installation.

In Windows Vista things are different. When Vista's User Account Control (UAC) is turned on, launching Setup.exe is not quite the same as running MSIEXEC.EXE /i mypackage.msi. The difference is that when Setup.exe is started, Vista runs it in "elevated" mode, which gives the process more privileges. MSIEXEC.EXE does not seem to run in elevated mode and therefore behavior of the installation may be different.

The issue seems to be manifesting itself most often when an MSI setup package made using Visual Studio executes custom action steps implemented as an Installer class. I am not sure what exactly happens but I noticed that MSI error 2689, which is a common result of failed custom action, will go away if installation initiated using Setup.exe instead of just clicking on .MSI file.

Bottom line: On Vista always start installations by launching Setup.exe instead of double-clicking .MSI file.

Another possibility to consider: if you were not a victim of computer virus attack in the last five years (Windows XP lifetime), then you are may want to simply turn Vista UAC off.

Comments [0] | | #