Category Archives: IIS7

IISAPP equivalent in IIS 7 and beyond

If there’s one change I hate about IIS 7 and beyond, it is the lack of the very useful IISAPP script that was present on IIS 6 installations.

Run it from a command prompt, and you will see a list of all running worker processes, the process id and the application pool name the process is serving. Very useful if you need to shut down a single site.

As I mentioned, that script was removed in IIS 7 and beyond. I find myself constantly running IISAPP without any luck several times a week, and I’ve decided that this is a habit that I cannot leave behind.

So, to solve the problem I’ve created a small .bat file called iisapp.bat and copied it to the C:\Windows\System32 folder. The content of the iisapp.bat file is just a single line, that does exactly the same as the old IISAPP did – just using the new APPCMD in IIS 7 instead:

%SystemRoot%\System32\inetsrv\appcmd list wp

Now I can call IISAPP and see a list of running applications:

IIS Application list in IIS 7

And now my day got a whole lot better. Since the BAT file was copied to the System32 folder, there’s no need to add anything to the PATH environment variable. This will work from any command prompt – just type iisapp and hit Enter.

The Integrated Programming model in IIS 7

IIS 7 comes with a bunch of improvements for developers. You can do a whole lot of exciting things even from web.config, but also from code.

To take advantage of the powerful integrated programming model, you need to set your application pool to use the Integrated pipeline mode. There’s no limit to what you can do.

I found a lot of great stuff in the book called Professional IIS 7 and ASP.NET Integrated Programming and learned a lot of useful stuff.

IIS 7 (or 7.5) is still the preferred way to develop, test and deploy ASP.NET applications, and as a developer you must stay up-to-date on what your tools and framework has to offer!

Multiple SSL certificates on IIS using host headers

In IIS SSL sites have seemed to be limited to only one site per network interface, since you (from IIS Manager) cannot specify a host header binding on the HTTPS protocol.

It turns out, that it is only a limitation in the UI. So to have e.g. two sites with their own dedicated SSL certificate we need to add a host header binding on port 443 from either appcmd, managed code or by editing the applicationHosts.config file.

I like managed code the most, so I’ve written a small method in C# that does the trick. You need to have two SSL certificates named www.ssl1.com and www.ssl2.com installed on the machine. I just created a self signed certificate for both of them using the IIS Manager.

using System.Security.Cryptography.X509Certificates;
using Microsoft.Web.Administration;

namespace IisSsl
{
    class Program
    {
        static void Main(string[] args)
        {
            using (ServerManager _serverManager = new ServerManager())
            {
                string siteName = "SSL2";
                string certName = "www.ssl2.com";

                X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
                store.Open(OpenFlags.ReadOnly);

                X509Certificate2 certificate = store.Certificates[0];

                Site site = _serverManager.Sites[siteName];

                if (site != null)
                {
                    site.Bindings.Add("*:443:" + certName,
                        certificate.GetCertHash(), store.Name);
                }
                store.Close();

                _serverManager.CommitChanges();
            }
        }
    }
}

Remember to add a reference to C:\Windows\System32\inetsrv\Microsoft.Web.Administration.dll in order to use the ServerManager class.

Migrate web.config to support the IIS 7 Integrated Pipeline

Whenever you deploy a website to IIS 7 that is not compliant with the IIS 7 integrated pipeline, you will get an error like this one:

iis7-integrated-pipeline-error

Not the great error message you get. It actually gives you the solution right away: Migrate Web.config to support the integrated pipeline. To do that, start a command prompt, and execute:

%SystemRoot%\system32\inetsrv\appcmd migrate config “test/”

After doing this, our Web.config is changed to support the IIS 7 integrated pipeline and we can see the website.

The Integrated Programming model in IIS 7

IIS 7 comes with a bunch of improvements for developers. You can do a whole lot of exciting things even from web.config, but also from code.

To take advantage of the powerful integrated programming model, you need to set your application pool to use the Integrated pipeline mode. There’s no limit to what you can do.

I found a lot of great stuff in the book called Professional IIS 7 and ASP.NET Integrated Programming and learned a lot of useful stuff.

IIS 7 (or 7.5) is still the preferred way to develop, test and deploy ASP.NET applications, and as a developer you must stay up-to-date on what your tools and framework has to offer!

Adding a Website to IIS7 programmatically

Some time ago, I blogged about Adding an Application Pool to IIS7 programmatically. The result was a new Application Pool, that uses the Integrated Pipeline in IIS7.

In this post I will show you how to add a new Website, that uses the Application Pool from the other blog post.

I’ve loaded the Console Application I used to add the Application Pool, and moved the logic from Main to a method called AddApplicationPool, to split it up nicely. It is actually even easier to add a website programmatically. Below is the code for doing just that:

private static void AddWebSite()
{
  ServerManager mgr = new ServerManager();

  if (!Directory.Exists(@"c:\inetpub\wwwroot\iis7test"))
  {
    Directory.CreateDirectory(@"c:\inetpub\wwwroot\iis7test");
  }

  // Add a new Site to the server, configured to use our the iis7test home directory.
  Site site = mgr.Sites.Add("MyWebSite", @"c:\inetpub\wwwroot\iis7test", 80);

  // Set the application pool name of the site, to use the MyAppPool application pool.
  site.ApplicationDefaults.ApplicationPoolName = "MyAppPool";

  // Clear all bindings.
  site.Bindings.Clear();

  // Make the site listen to incoming HTTP requests using host header iis7test, on port 80.
  site.Bindings.Add("*:80:iis7test", "http");

  // Set auto start to true.
  site.ServerAutoStart = true;

  // Commit the changes
  mgr.CommitChanges();
}

Notice how we add Bindings to the website. Bindings is the information that tells IIS7 when to serve our website. We use this string to configure bindings: *:80:iis7test. The first * tells IIS to listen on all IP addresses on your system. 80 is the port number, and iis7test is the host header value for this site.

To browse our website, we need to add iis7test to the computers hosts file (located in %WINDIR%\System32\Drivers\etc), and point it to 127.0.0.1.

The Integrated Programming model in IIS 7

IIS 7 comes with a bunch of improvements for developers. You can do a whole lot of exciting things even from web.config, but also from code.

To take advantage of the powerful integrated programming model, you need to set your application pool to use the Integrated pipeline mode. There’s no limit to what you can do.

I found a lot of great stuff in the book called Professional IIS 7 and ASP.NET Integrated Programming and learned a lot of useful stuff.

IIS 7 (or 7.5) is still the preferred way to develop, test and deploy ASP.NET applications, and as a developer you must stay up-to-date on what your tools and framework has to offer!

Adding an Application Pool to IIS7 programmatically

Internet Information Services 7 (IIS7) has a great new set of features regarding configuration. Using the Integrated Configuration system, you can configure your server from XML files, the IIS7 manager, the command prompt using the APPCMD tool, but IIS7 also lets you manage your server from managed code in a very intuitive manner.

If you navigate to the %WINDIR%\System32\InetSrv folder in Windows Vista, you’ll find all the executables, DLL’s and XML (.config) configuration files you need. It doesn’t matter if you use the IIS7 Manager, managed code or the APPCMD command-line based tool to manage your server – at the end of the day you are changing an XML file. That is applicationHost.config which is located here: C:\Windows\System32\inetsrv\config\applicationHost.config.

The integrated configuration system on IIS7 is great news for hosters, and web developers. Hosters can easily automate server management through managed code, and as a web developer, you can configure your server from your web.config file, which makes it easy to move your web application from development, to test, and further up towards production. Read my post on how to set a websites default document, from within the web application’s web.config file.

In this post, I will create an application pool on my local IIS7.

Launch Visual Studio 2005 or 2008 – whatever you’ve got will work.

Create a new Console Application, and give it a name of your own choice.

Right click References in the Solution Explorer and add a new reference.

image

Locate Microsoft.Web.Administration.dll from the C:\Windows\System32\inetsrv folder.

To access IIS7, we use the ServerManager class, as shown below.

 1: using System;
 2: using System.Collections.Generic;
 3: using System.Linq;
 4: using System.Text;
 5: using Microsoft.Web.Administration;
 6: 
 7: namespace Iis7ManagementTest
 8: {
 9:   class Program
 10:   {
 11:     static void Main(string[] args)
 12:     {
 13:       ServerManager mgr = new ServerManager();
 14: 
 15:       // Add a new application pool called MyAppPool
 16:       ApplicationPool myAppPool = mgr.ApplicationPools.Add("MyAppPool");
 17: 
 18:       // Configure my new app pool to start automatically.
 19:       myAppPool.AutoStart = true;
 20: 
 21:       // What action should IIS take when my app pool exceeds 
 22:       // the CPU limit specified by the Limit property
 23:       myAppPool.Cpu.Action = ProcessorAction.KillW3wp;
 24: 
 25:       // Use the Integrated Pipeline mode
 26:       myAppPool.ManagedPipelineMode = ManagedPipelineMode.Integrated;
 27: 
 28:       // Set the runtime version of ASP.NET to 2.0
 29:       myAppPool.ManagedRuntimeVersion = "v2.0";
 30: 
 31:       // Use the Network Service account
 32:       myAppPool.ProcessModel.IdentityType = ProcessModelIdentityType.NetworkService;
 33: 
 34:       // Shut down after being idle for 5 minutes.
 35:       myAppPool.ProcessModel.IdleTimeout = TimeSpan.FromMinutes(5);
 36: 
 37:       // Max. number of IIS worker processes (W3WP.EXE)
 38:       myAppPool.ProcessModel.MaxProcesses = 1;
 39: 
 40:       // Commit the changes
 41:       mgr.CommitChanges();
 42:     }
 43:   }
 44: }

After the application has been executed, we will see our new application pool inside the IIS7 Manager:

image

That’s all for now. In another blog post I will show how to add a new web site, that will use our new application pool – also from managed code.

kick it on DotNetKicks.com

 

The Integrated Programming model in IIS 7

IIS 7 comes with a bunch of improvements for developers. You can do a whole lot of exciting things even from web.config, but also from code.

To take advantage of the powerful integrated programming model, you need to set your application pool to use the Integrated pipeline mode. There’s no limit to what you can do.

I found a lot of great stuff in the book called Professional IIS 7 and ASP.NET Integrated Programming and learned a lot of useful stuff.

IIS 7 (or 7.5) is still the preferred way to develop, test and deploy ASP.NET applications, and as a developer you must stay up-to-date on what your tools and framework has to offer!

Configuring IIS 7 default document from web.config

IIS 7 has a lot of changes regarding the configuration model. Using the Integrated Configuration System in IIS 7 you can set configuration of your server on different levels, compared to IIS 6, where the ASP.NET developer were more restricted. Configuring IIS 7 from an ASP.NET Web Application’s web.config file works from both ASP.NET 2.0 and ASP.NET 3.5. Note that the server can be restricted to lock certain configuration settings from above the application level, you might encounter this if your website runs in a shared hosting environment.

Setting up the website

To have a test website, I will setup a new website on my Vista machine running IIS 7. I don’t want the website to run under the Default Web Site, so first thing, I’ll add a hostname to my hosts file. This is located in the drivers\etc folder of your windows directory’s system32 folder. Add the following line:

127.0.0.1         iis7test

Open up Internet Information Services (IIS) Manager, and create a new Application Pool. Name it iis7test, and leave the settings as default:

image

Add a new website with the following settings:

image

This should get us started. Open up Visual Studio 2008 (2005 will also work). Open the website you just created inside IIS.

image

The only item in the website is a web.config. Add a new Web Form called Test.aspx.

Right-click the Test.aspx file and click View in browser. You could get an HTTP Error 500.00, like this:

image

To get rid of it, set impersonate to false in the web.config file by adding this line to the system.web section:

<identity impersonate=”false” />

Now your site should work fine. Edit the Test.aspx file, so it has some content. Just write Test IIS 7 or something in the HTML mark-up.

If you right-click the website icon in the Solution Explorer, and click View in browser, you will get an error like the one bellow:

image

That is because our website does not have any pages that match the name of the default documents on IIS. If you don’t want to be limited by the few default documents that comes with IIS out-of-the-box, you can add your own from web.config by adding these lines:

<system.webServer>
<defaultDocument>
<files>
<clear />
<add value=”Test.aspx” />
</files>
</defaultDocument>
</system.webServer>

Maybe the system.webServer section already existed in your web.config file. If so, just add the defaultDocument section. Here you can specify all the filenames that should act as a default document in IIS 7. The <clear /> line is optional. If you want to keep the default settings, and only add your own – just delete that line.

Now when we save the new web.config file, and refresh the browser we se our Test.aspx file:

image

This setting is just one of many that you can specify in your application’s web.config file. In the near future I’ll be blogging more about specific settings you can use to configure IIS 7 from ASP.NET.

Technorati Tags: ,

kick it on DotNetKicks.com

The Integrated Programming model in IIS 7

IIS 7 comes with a bunch of improvements for developers. You can do a whole lot of exciting things even from web.config, but also from code.

To take advantage of the powerful integrated programming model, you need to set your application pool to use the Integrated pipeline mode. There’s no limit to what you can do.

I found a lot of great stuff in the book called Professional IIS 7 and ASP.NET Integrated Programming and learned a lot of useful stuff.

IIS 7 (or 7.5) is still the preferred way to develop, test and deploy ASP.NET applications, and as a developer you must stay up-to-date on what your tools and framework has to offer!

How to handle IIS Event id 1009 (Event id 5011 on IIS 7)

Recently at work we had some serious production environment issues. Our web application basically made the IIS application pool terminate unexpectedly. And we didn’t get a single stack trace or a line of code. The only thing that was logged inside of the Windows Event Viewer, was event id 1009, which basically told that the application pool serving our app terminated unexpectedly. And that was it. All active user sessions were wiped, and the users had to login again.

The error started after we did a major upgrade. A lot of our code had changed since the previous version, so we set up an new website and application pool inside IIS 6.0 for the new version, so we could upload the new application, and then turn off the old one, to get as seamless an upgrade as possible. It worked fine, and we were happy. Until a few hours later, when we saw our users were logged off.

At first we thought it was IIS settings we had done wrong, so we did a complete comparison with the old website and application pool to see if we forgot anything. There was no difference at all. After a while, we realized that the only thing that could make the IIS crash like that, was our own code. But with no clue of where the danger in our code were – we were lost.

After some time, we got WinDbg attached to the worker process of IIS, serving our application. We caught a few memory dumps, but those were not of the exception we were looking for.

Later I found an HttpModule for ASP.NET. Basically the .Net framework 2.0 has changed the way it handles exceptions from other threads in IIS. In ASP.NET 1.1, unhandled exceptions from asynchronous threads inside IIS were ignored. But in ASP.NET 2.0, those unhandled exceptions makes the IIS application pool crash.

Make the IIS crash yourself

So try to do this. Create a new ASP.NET 2.0 website running on your local IIS. You only need a single page, so you’re fine with the default.aspx Visual Studio creates for you. Add a button to the page, and create an event handler for the buttons OnClick event.

Add this to your code-behind:

  /// <summary>
  /// Handles the Click event of the btnMakeCrash control.
  /// </summary>
  /// <param name="sender">The source of the event.</param>
  /// <param name="e">The EventArgs instance containing the event data.</param>
  protected void btnMakeCrash_Click(object sender, EventArgs e)
  {
    ThreadPool.QueueUserWorkItem(new WaitCallback(MakeIisCrash));
  }

  /// <summary>
  /// Makes the IIS crash.
  /// </summary>
  /// <param name="stateInfo">The state info.</param>
  private void MakeIisCrash(object stateInfo)
  {
    // Instantiate the DataSet to null
    DataSet ds = null;

    // Make an unhandled NullReferenceException
    ds.CaseSensitive = true;
  }

The buttons click event handler uses the ThreadPool to execute the MakeIisCrash() method. This method instantiates a DataSet as null, and the sets a property. Since the DataSet is null, this throws a NullReferenceException which is not handled, as you can see.

Click the button, and see how IIS will crash.

You can sense that your computer is working harder – that is because IIS terminates the application pool. If you go and check the Windows Application log, you can see that is has added an error:

image

Now this doesn’t tell you much. Imagine if you had hundreds of thousands line of code – how would you find the cause of the error?

Inside Visual Studio, add a new class to the website – call it UnhandledExceptionModule, and apply this code:

#region Using

using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Web;

#endregion

/// <summary>
/// Handles all unhandled exceptions from in the current AppDomain. 
/// 
/// Works great to catch unhandled exceptions thrown by IIS's child threads, /// which will make the application pool terminate unexpectedly 

/// without logging. This makes sure your Exception /// is logged to the Application event log.
/// </summary>
public class UnhandledExceptionModule : IHttpModule
{
  #region Fields

  private static int _UnhandledExceptionCount = 0;
  private static string _SourceName = null;
  private static object _InitLock = new object();
  private static bool _Initialized = false;

  #endregion

  #region IHttpModule members

  public void Init(HttpApplication app)
  {

    // Do this one time for each AppDomain.
    if (!_Initialized)
    {
      lock (_InitLock)
      {
        if (!_Initialized)
        {
          string webenginePath = Path.Combine(RuntimeEnvironment.GetRuntimeDirectory(), "webengine.dll");

          if (!File.Exists(webenginePath))
          {
            throw new Exception(String.Format(CultureInfo.InvariantCulture,                 "Failed to locate webengine.dll at '{0}'.  This module requires .NET Framework 2.0.", webenginePath));
          }

          FileVersionInfo ver = FileVersionInfo.GetVersionInfo(webenginePath);
          _SourceName = string.Format(CultureInfo.InvariantCulture, "ASP.NET {0}.{1}.{2}.0", ver.FileMajorPart,                 ver.FileMinorPart, ver.FileBuildPart);

          if (!EventLog.SourceExists(_SourceName))
          {
            throw new Exception(String.Format(CultureInfo.InvariantCulture,                 "There is no EventLog source named '{0}'. This module requires .NET Framework 2.0.", _SourceName));
          }

          AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(OnUnhandledException);

          _Initialized = true;
        }
      }
    }
  }

  public void Dispose()
  {
  }

  #endregion

  #region UnhandledException event handler

  public void OnUnhandledException(object o, UnhandledExceptionEventArgs e)
  {
    // Let this occur one time for each AppDomain.
    if (Interlocked.Exchange(ref _UnhandledExceptionCount, 1) != 0)
      return;

    StringBuilder message = new StringBuilder("\r\n\r\nUnhandledException logged by UnhandledExceptionModule:\r\n\r\nappId=");

    string appId = (string)AppDomain.CurrentDomain.GetData(".appId");
    if (appId != null)
    {
      message.Append(appId);
    }

    Exception currentException = null;
    for (currentException = (Exception)e.ExceptionObject; currentException != null; currentException = currentException.InnerException)
    {
      message.AppendFormat("\r\n\r\ntype={0}\r\n\r\nmessage={1}\r\n\r\nstack=\r\n{2}\r\n\r\n",
                           currentException.GetType().FullName,
                           currentException.Message,
                           currentException.StackTrace);
    }

    EventLog Log = new EventLog();
    Log.Source = _SourceName;
    Log.WriteEntry(message.ToString(), EventLogEntryType.Error);
  }

  #endregion
}

Modify the httpModules section inside web.config to look lige this:

        <httpModules>            <add type="UnhandledExceptionModule" name="UnhandledExceptionModule"/>        </httpModules>

This is your new friend. It is a must for any ASP.NET 2.0 application running in production environment. This will catch your exception, and write the message and the stack trace to the Windows Application Event log, and now you can see what caused the crash:

image

So after we applied this HttpModule to our production environment, we get a nice entry in our Application event log from ASP.NET. It includes a stack trace, which makes us able to find the problem, and fix it!

Further reading regarding ASP.NET production environment issues:

Hope this will help someone.

Technorati Tags: , , ,

kick it on DotNetKicks.com