By Scott Forsyth
November 28, 2003
When ASP.NET v1.1 was released, it became my project to find the best way to support this for our client base at ORCS Web, Inc. We needed to be able to switch versions of the Framework per site as smoothly as possible. Requiring everyone to move to version 1.1 wouldn't work and leaving everyone on version 1.0 wouldn't work either, so we had to have a way to pick and choose and to make the switch without interrupting other sites on the same server.
Is this for you?
Before I go any further, I should mention the reasons why this applies to the average developer as well as the system administrator. Currently there are two released versions of ASP.NET but there are already multiple alpha and beta versions and there will continue to be more. To be able to quickly switch between versions with just a couple clicks and keystrokes makes development and testing against multiple frameworks easy. Granted, aspnet_regiis.exe will accomplish this as I’ll mention below, but it can take over 30 seconds. Imagine being able to immediately switch between Version 1.0, 1.1 and 2.0 (v2.0 is in Alpha at the time of this writing) without setting up multiple sites in IIS. If this interests you, read on because this doesn't just apply to a system administrator.
My 4 objectives were:
1) To be able to update a single site to the new framework
2) To be able to revert back if desired
3) To have an easy way for anyone on our team to be able to do it consistently and quickly
4) To do this without affecting the other sites on the same server
Stating the Obvious
The most obvious way to do this was to use aspnet_regiis.exe supplied with ASP.NET. To use this method I would run "C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\aspnet_regiis.exe -s W3SVC/50/ROOT". This would update the Version of the framework for the site with ID 50 and not update the other sites on this server. It has the flexibility required to set this for the whole server, per site or even per sub-folder. The problem I immediately ran into was that both Internet Information Server (IIS) service and Session State would reset, causing every site on the server to be down for up to 2 minutes. Ouch. The strange thing is that the whole server was affected, even when running this against a single site. This met the first 3 objectives. Unfortunately all sites on that server would be affected, blowing the 4th objective out of the water.
The other option I considered is manually changing all the script mappings in the IIS snap-in. To change this manually, select the "Home Directory" tab in IIS and click on the "Configuration" button. The "Mappings" tab has all the mappings. The path to the alternate aspnet_isapi.dll can be changed here. The problem is that this didn't meet the 3rd objective because of the large number of script mappings that had to be manually changed.
Is a better solution possible?
Needless to say, I had to go back to the drawing board to find something that would work better. My initial guess was that doing this from script would be difficult and would probably cause a similar interruption of service to IIS. Fortunately I was wrong on both points. Not only did it turn out to be a simple undertaking but there was zero, yes zero, impact on other sites. Even the site being changed was not affected, other than Session State being reset. That not only met all four of my objectives, it exceeded my expectations.
Using WSH I use an Input box and ask for the server, Site ID (more on the later) and the version to change to. Then ADSI is used to retrieve the current script mappings and do a search-and-replace from the previous version to the new version.
There are a number of ways to obtain the siteID in IIS. My favorite is to go into the properties of the site from the IIS snap-in and click on the "Properties" button in the Logging section. At the bottom, you'll notice a "Log file name". It will start with W3SVC??. For example, it might be W3SVC1 or W3SVC99. It's the number after the W3SVC that counts. (i.e. W3SVC1 is SiteID 1, W3SVC99 is SiteID 99).
At the risk of boring the casual reader I feel I must mention one more thing that was tested. The script mappings are usually inherited from the default mappings for the server. IIS uses its own storage system called the Metabase which is similar in concept to Windows Registry. The first time a site or sub-folder within a site is assigned specific script mappings, it will write its own copy of the script mappings to its area of the metabase. Any new changes to the script mappings will be written against the new copy. ChangeFramework.vbs will work correctly whether or not the custom script mappings are in place.
To use this script, simply save to your computer and double-click. This is freely available to use by all, but I request that you keep the header in place to give credit to both myself and ORCS Web, Inc. There is no warranty whatsoever so if your computer blows up or falls over dead, don't come looking to me for help. But, the disclaimer aside, we've been running this for over 1/2 year on live production servers and it was worked 100% of the time without incident and I personally attest to its stability and trustworthiness.
The script itself can be found at http://www.orcsweb.com/articles/ChangeFramework.zip
It should be pretty obvious by this doesn't install the framework. It simply switches between versions that are already installed on your computer.
Scott Forsyth is Director of IT at ORCS Web, Inc. - a company that provides managed hosting solutions for clients who develop and deploy their applications on Microsoft Windows platforms. Services include shared hosting, dedicated hosting, and webfarm hosting, with specialty in .Net, SQL Server, and architecting highly scalable solutions.
Starting in the first version of ASP.NET, Microsoft has provided a tool to control which version of the framework is registered in IIS. This tool, aspnet_regiis.exe, is quite flexible and with the right understanding of how IIS and ASP.NET work, can be used for most any situation.
The most common parameter is -i. This is the full blown registration of the framework in IIS, including all sites and all vdirs. For example, let's say you wanted your entire server to be registered using ASP.NET v2.0, then you would navigate to the v2.0 framework folder (%windir%\Microsoft.NET\Framework\v2.0.50727) and type aspnet_regiis -i. Likewise, you can navigate to (%windir%\Microsoft.NET\Framework\v1.1.4322) and run the same command to set v1.1 on all sites. This is a great way to repair a broken installation or force a particular framework version to apply to your whole server.
But this catch-all registration is too aggressive for many production servers. That's where the other parameters come in.
To see a detailed list of commands, type aspnet_regiis /? from the command prompt. I'm going to explain two of them: -lk and -sn. With these commands, we can apply the script mappings on just some of the sites on the server and update the default.
Careful on Production Servers
Note: First a disclaimer. Running any aspnet_regiis commands that make a change to IIS will cause all sites on the server to have a short interruption of service. Even if you run the path specific commands which I’ll explain below, all sites will have some downtime. To make changes on production servers without any downtime, you'll need to write a solution to update the script mapping directly. Here's an old article of mine that explains this in more depth:
http://www.orcsweb.com/articles/change_framework.aspx (Someday I'll rewrite that article with an updated script to handle more than 2 versions of the framework, and IIS6 application pool support.)
While I'm offering disclaimers, make sure not to run multiple versions of the framework in the same Application Pool in IIS6.0:
Let me digress again and explain how IIS inheritance works for the script mappings. IIS has a path structure similar to the file system on your computer. For example, the web part of the structure starts with /W3SVC/. Site #1 stores the script mappings in /W3SVC/1/ROOT/. Site #51 stores them in /W3SVC/51/ROOT/, and so on. If the script mappings are specifically set on a particular path then IIS will use those settings. But if they aren't set then it will use the settings from the site or server root.
ASP.NET Version Defaults
When ASP.NET v1.1 was released, if you ran the install, it would apply your settings to all sites on the server, thus changing your framework version from v1.0 to v1.1. This meant that you had to be careful if you wanted to keep version 1.0 as the default. The install had some command line options to give more flexibility.
Version 2.0 of the framework is different and not as aggressive during the installation. Now it doesn't make itself the default and you are required to specifically set it as the default if that is what you want. This is a good thing and is a better behavior than the v1.1 installation.
Don't forget to take a backup
Warning: At this point, make sure to get a backup of IIS before continuing. If you do something wrong, you can restore it and everything will be brought back to its original state.
Displaying The Current Settings
Displaying The Current Settings
The aspnet_regiis tool has a neat way to see what is currently applied in IIS right now. You can do this by typing aspnet_regiis -lk from any framework folder. This will give something like this: (you can do this read-only command without any downtime on your server)
Notice on this test server that the root, site #3 and site #6 are using v1.1 of the framework and site #1 and #7 are using v2.0. (Here is an article to find out which site is using which SiteID: http://weblogs.asp.net/owscott/archive/2005/07/29/421058.aspx)
Notice the gaps in numbers as #2, #4 and #5 aren't set. This means that they will inherit their settings from /W3SVC/ which is currently using v1.1.
Now, the issue we have is that when setting up new sites, they will always use version 1.1 of the framework. Since v2.0 has all of the latest and greatest features, we want new sites to use v2.0 but make sure that existing sites aren't changed. In our example here, let's say that we want to upgrade the server to use v2.0 of the framework as the default version, but we don't want sites #2, #3 or #6 to be upgraded.
If we run aspnet_regiis -i then we'll force everything to version 2.0 which we don't want. And if we upgrade just the root, then too many of the sites will be upgraded, which is also what we don't want.
The trick is to force all sites that you don't want to upgrade to use v1.1, and then we can upgrade the root to v2.0. Then all new sites created after this will use v2.0.
Sites #3 and #6 are easy, they are already done for us. But site #2 needs to be set to specifically use v1.1 of the framework. This can be done by running aspnet_regiis from the v2.0 framework folder using this command: aspnet_regiis -sn W3SVC/2/ROOT/. Now running aspnet_regiis -lk will return this:
For the purpose of this example, we're going to let site #4 and #5 continue to inherit from the root, so after the next step they will be upgraded (using inheritance) to use version 2.0 of the framework.
The final step is to update the W3SVC/ node without touching anything else. As I'm sure you've guessed by now, this is done using: aspnet_regiis -sn W3SVC/. Now we're done, let's look at the final result:
Success! Now sites #4 and #5 and all new sites will use the W3SVC/ setting, which is v2.0. Sites #1 and #7 will also use v2.0 because they were specifically set. Sites #2, #3 and #6 will continue running version 1.1 of the framework.
We've applied version 2.0 of the framework as the system default while allowing some sites to continue to run version 1.1 of the framework.
各位在同一电脑上同时安装并运行.net 1.1 和 .net 2.0 两个版本的朋友要小心啊！
您的项目是不是时不时会出现 Server Application Unavailable 错误呢？或者一直连续都出这个错误!
今天帮一个老师升级一个web的心理测评系统.那个系统原来是ASP.NET 1.1的,新版本是ASP.NET 2.0的..(PS:那台服务器上面还装其他的ASP.NET程序,用的是ASP.NET1.1的.)
2、在服务器的IIS上新建一个虚拟目录，然后 将其配置成可以执行脚本的应用程序，（过程与创建.net Framework 1.1版本的程序相同。） 然后，将此虚拟目录的.net Framework 配置成2.0。
Server Application Unavailable
The web application you are attempting to access on this web server is currently unavailable. Please hit the "Refresh" button in your web browser to retry your request.
Administrator Note: An error message detailing the cause of this specific request failure can be found in the application event log of the web server. Please review this log entry to discover what caused this error to occur.
经过仔细阅读了IIS帮助文档，才发现，原来这个错误是由 IIS6 应用程序隔离机制造成的。IIS默认的应用程序隔离机制被称为：“工作进程隔离模式”，在此模式中，应用程序被分为多个组，每个组就是一个“应用程序池” ，每个应用程序池之间是相互隔离的。 隔离的好处当然就是安全啦，稳定啦，等等。IIS中的每个应用程序池由一个“工作进程”分别进行管理，也就是"W3wp.exe" 。如果有多个应用程序池中的程序运行，我们就能看到多个w3wp.exe。 我们平时新建的虚拟目录都默认被指向IIS6的“DefaultAppPool" 中， 所以在默认情况下，不管你有多少个asp.net程序在运行，在“Windows任务管理器”中你只能看到一个w3wp.exe进程。
出现上述错误的原因是： .net Framework 2.0的程序与.net Framework1.1(或1.0)的程序被放入同一个应用程序池（默认情况下放入DefaultAppPool池），也就是由同一个工作进程: w3wp.exe 进行管理，而单个工作进程是无法同时管理不同的程序（或者不同版本的程序）的。如果先访问.net framework 1.1的页面，则工作进程先加载并管理了 1.1版本的程序集，此时访问.net framework 2.0的web程序页面，Server Application Unavailable 错误就出来了。 反之，如果在默认应用程序池的w3wp.exe尚未启动前先访问了 2.0的web程序（此时应用程序集已经加载了.net framework2.0的Web程序集），再访问1.1或1.0的Web程序页面时，同样会出现“服务器应用程序不可用” 这样的中文提示。（您可以结束掉以前的w3wp.exe进行测试。）
解决办法： 在IIS中新建一个应用程序池,叫"ASP.NET2.0"吧，然后选中那个系统的虚拟目录，点“属性”－》在“应用程序池” 中选择刚才新建的的应用程序池，点击“确定”。