Microsoft Bob

Just a short, simple blog for Bob to share some tips and tricks.

Be sure to check out my non-technical blog at www.geekybob.com.

Month List

Video: What's New with Internet Information Services (IIS) 8: Performance, Scalability, and Security Features

The folks in the TechEd group have uploaded the video from my "What's New with Internet Information Services (IIS) 8: Performance, Scalability, and Security Features" presentation to YouTube, so you can view the video online.

You can also download the slides and the WMV/MP4 for my presentation at the following URL:

http://channel9.msdn.com/Events/TechEd/NorthAmerica/2012/WSV332

One quick side note: around 38:55 during the video, I had just asked the audience if anyone had used the IIS Configuration Editor, when a tremendous thunderclap resounded outside - this prompted a great laugh from audience members. After the presentation had ended, a couple people came up and jokingly asked how I had managed to stage that so well.

Smile

Posted: Sep 01 2012, 14:59 by Bob | Comments (0)
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: FTP | IIS | Windows
Social Bookmarks: E-mail | Kick it! | DZone it! | del.icio.us

Troubleshooting Custom FTP Providers with ETW

I recently received a question from a customer about troubleshooting custom FTP providers, and I recommended using the FTP service's Event Tracing for Windows (ETW) features in order to help troubleshoot the problem. I've helped a lot of customers use this little-known feature of the FTP service, so I thought that it would make a great subject for a quick blog.

By way of explanation, the FTP service in IIS 7.5 and IIS 8.0 allows developers to write their own custom functionality, and over the past several years I have written several walkthroughs and blogs that illustrate how you can create your own custom FTP providers:

That being said, sometimes things go wrong, and when that happens, I use some FTP ETW troubleshooting tricks that I'd like to share.

Setting up FTP ETW Tracing

Several years ago I wrote a blog about FTP and ETW Tracing, where I described how to turn on the FTP service's ETW tracing through a batch file, and then it used Log Parser to render the output in a datagrid for analysis. In the interests of completeness, here is the batch file again:

@echo off

rem======================================================================

echo Verifying that LogParser.exe is in the path...
LogParser -h >nul 2>nul
if errorlevel 1 (
  echo.
  echo Error:
  echo.
  echo   LogParser.exe is was not found. It is required for parsing traces.
  echo.
  echo Recommended actions:
  echo.
  echo   - If LogParser is installed then fix the PATH
  echo     variable to include the LogParser directory
  echo.
  echo   - If LogParser is not installed, then install
  echo     it from the following location:
  echo.
  echo   http://www.microsoft.com/downloads/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07
  echo.
  goto :EOF
) else (
  echo Done.
  echo.
)

rem======================================================================

echo Starting the ETW session for full FTP tracing...
logman start "ftp" -p "IIS: Ftp Server" 255 5 -ets
echo.
echo Now reproduce your problem.
echo.
echo After you have reproduced your issue, hit any key to close the FTP
echo tracing session. Your trace events will be displayed automatically.
echo.
pause>nul

rem======================================================================

echo.
echo Closing the ETW session for full FTP tracing...
logman stop "ftp" -ets

rem======================================================================

echo.
echo Parsing the results - this may take a long time depending on the size of the trace...
LogParser "select EventTypeName, UserData from ftp.etl" -e 2 -o:DATAGRID -compactModeSep " | " -rtp 20

When you save and run this batch file, it will display something like the following:


C:\FTP_ETW.cmd

Verifying that LogParser.exe is in the path...
Done.

Starting the ETW session for full FTP tracing...
The command completed successfully.

Now reproduce your problem.

After you have reproduced your issue, hit any key to close the FTP tracing session. Your trace events will be displayed automatically.
 

When you see this displayed, you will need to reproduce your problem, and FTP's ETW tracing will record the troubleshooting information.

Once you have reproduced your problem, hit a key to end the ETW session, and you will see the following message displayed:


Closing the ETW session for full FTP tracing...
The command completed successfully.

Parsing the results - this may take a long time depending on the size of the trace...
 

The batch file will eventually call Log Parser to parse the ETW events, and a dialog like the following will be displayed:

Troubleshooting Custom FTP Providers with ETW Tracing

Now that you know how to set up FTP's ETW tracing, let's examine what you should be looking for in the tracing information.In all of the examples in this blog, I am using the XML-based authentication provider that is documented in the How to Use Managed Code (C#) to Create an FTP Authentication Provider using an XML Database walkthrough.

The following illustration highlights several lines that show the FTP service starting its authentication process, loading my custom authentication provider, and ending the authentication process after I have successfully logged in:

This example shows what everything looks like when it works as expected, so now let's look at what happens when something goes wrong.

If I use the same provider, but I enter my username or password incorrectly, I will see the following lines in the trace:

This example informs you that the provider was loaded successfully, but the logon failed. The error code that is returned is 0x8007052E - this hexadecimal 32-bit value can be split into 16-bit values:

  • 8007 - This code informs you that this is a Win32 error.
  • 052E - This code coverts to 1326 in decimal, and if you enter "NET HELPMSG 1326" from a command-prompt, that will tell you that the error was "Logon failure: unknown user name or bad password."

If I continue to use the same provider as earlier, and I delete the XML file that my provider uses, then I will receive the following error:

Once again, this example informs you that the provider was loaded successfully, but an error occurred. In this specific case you see the actual details that the XML file exists, and that is an error that is returned by a throw() statement in the provider. The error code that is returned is 0x80070057 - and once again this hexadecimal 32-bit value can be split into 16-bit values:

  • 8007 - This code informs you that this is a Win32 error.
  • 0057 - This code coverts to 87 in decimal, and if you enter "NET HELPMSG 87" from a command-prompt, that will tell you that the error was "The parameter is incorrect."

If I replace the missing XML file for the provider, but I remove all of the permissions to the file, I get the following error:

As in the previous examples, this informs you that the provider was loaded successfully, but an error occurred. You can't look up the 0x80131500 error code by using "NET HELPMSG" from a command-prompt, but that doesn't matter since the error description informs you of the problem - access to the path where the file is located was denied.

If I enter a bad provider name, I get the following error:

Unlike the previous examples, this informs you that the provider was not loaded successfully. The description for this error informs you that it could not load the provider, and it gives you the assembly information. In addition to the error description, the error code that is returned by the FTP service is 0x80070002 - and once again this hexadecimal 32-bit value can be split into 16-bit values:

  • 8007 - This code informs you that this is a Win32 error.
  • 0002 - This code is obviously 2 in decimal, so if you enter "NET HELPMSG 2" from a command-prompt, that will tell you that the error was "The system cannot find the file specified."

So now let's look at a common perplexing problem:

This example shows the same 0x8007052E error code that we looked at in a previous example, but you'll notice that any reference to the provider is conspicuously absent from the trace - this means that the FTP service made no attempt to load the custom authentication provider. In this specific case, even though I had correctly registered my custom FTP authentication provider on the system, I had not added or enabled the custom authentication provider for my FTP site.

Summary

In this blog I showed you how to troubleshoot several different errors with FTP custom authentication providers by using FTP's ETW features.

As a parting thought, I should point out that the most-common error that I run into when creating my own providers is the last example. Believe it or not, I nearly always miss a step when I am creating a new provider and I forget to add a setting here or there which will cause the FTP service to completely ignore my provider. A perfect example is when I am writing custom home directory providers - I always remember to add the provider to the global list of FTP providers, and I usually remember to add the provider to the list of custom features for my FTP site, but I forget to configure my FTP site to use custom user isolation and my provider is ignored. (Darn, darn, darn...)

;-]

Note: This blog was originally posted at http://blogs.msdn.com/robert_mcmurray/
Posted: Aug 28 2012, 16:33 by Bob | Comments (0)
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: FTP | Extensibility
Social Bookmarks: E-mail | Kick it! | DZone it! | del.icio.us

Advanced Log Parser Charts Part 5 - Creating a Generic Chart Color Script

In Part 5 of this series, I'll show you how to create a generic script that you can use to add some color to your Log Parser charts. As I mentioned in Part 1 of this series, the default colors for Log parser charts are really dull and boring. For example, if I parse one month's worth of log files from one of my low-volume websites with the following query:

logparser.exe "SELECT date,COUNT(*) AS Hits INTO HITS.gif FROM *.log GROUP BY date ORDER BY date" -i:w3c -o:CHART -chartType:ColumnClustered -chartTitle:"" -q:ON

Log Parser will create the following ugly daily hits chart:

Generic Color Change Script

Here's the background story for this blog: I have a collection of scripts that I use to format my charts, several of which have faithfully served as the fodder for this blog series. With that in mind, I had a situation recently where I was querying logs with a series of data just like this, and of course the resulting charts were kind of hideous to look at. In one of the scripts that I often use, I create an array of colors to use, and then I apply the various colors to the individual data points in the series.

In the past I have always hard-coded the length for the array of colors based on the data that I am working with, but in this situation I had no idea how many data points I would have, so I decided to put together a quick script with an array that would work with a series of any size.

Here's the resulting script:

// Set a default color for the chart's data.
chart.SeriesCollection(0).Interior.Color = "#ffcccc";

// Define a short array of colors.
var colors = [
    "#ffff99", "#ff99ff", "#ff9999",
    "#99ffff", "#99ff99", "#9999ff",
    "#ffffcc", "#ffccff", "#ffcccc",
    "#ccffff", "#ccffcc", "#ccccff"
];

// Loop through the data points in the series.
for (x=0;x<chart.SeriesCollection(0).Points.Count;++x)
{
    // Set the color for the data point based on modulo division of the array length.
    chart.SeriesCollection(0).Points(x).Interior.Color = colors[x % colors.length ];
}

That's all that there is to the script - it's pretty simple. If I take the above script and save it as "FormatChart.js", I can use that script with my Log Parser query from earlier by adding an extra parameter to the command:

logparser.exe "SELECT date,COUNT(*) AS Hits INTO HITS.gif FROM *.log GROUP BY date ORDER BY date" -i:w3c -o:CHART -chartType:ColumnClustered -chartTitle:"" -q:ON -config:FormatChart.js

Now Log Parser will create the following daily hits chart with a great deal more color to it:

Okay - perhaps that's not the best color palette, but you get the idea. It looks even better when I change the query to use 3D charts:

logparser.exe "SELECT date,COUNT(*) AS Hits INTO HITS.gif FROM *.log GROUP BY date ORDER BY date" -i:w3c -o:CHART -chartType:Column3D -chartTitle:"" -q:ON -config:FormatChart.js

The above query creates the following chart:

Color Changing Pie Charts

I'd like to make a quick change to the script in order to make it work a little better with a pie chart:

// Set a default color for the chart's data.
chart.SeriesCollection(0).Interior.Color = "#cccccc";

// Define a short array of colors.
var colors = [
    "#cc3333", "#3333cc", "#33cc33",
    "#33cccc", "#cccc33", "#cc33cc"
];

// Loop through the data points in the series.
for (x=0;x<chart.SeriesCollection(0).Points.Count;++x)
{
    // Set the color for the data point based on modulo division of the array length.
    chart.SeriesCollection(0).Points(x).Interior.Color = colors[x % colors.length ];
}
// Rotate the chart 180 degrees - just so it looks a little better.
chartSpace.Charts(0).PlotArea.RotateClockwise();
chartSpace.Charts(0).PlotArea.RotateClockwise();

For this query I'd like to see a break down by HTTP status, and this necessitates some small change to the Log parser query:

logparser.exe "SELECT sc-status AS Status,COUNT(*) AS Hits INTO HITS.gif FROM *.log GROUP BY Status ORDER BY Status" -i:w3c -o:CHART -chartType:PieExploded3D -chartTitle:"" -q:ON -config:FormatChart.js

The above query creates the following chart:

Summary

That wraps it up for this blog - I hope that I've given you some ideas for ways that you can easily add some colors to some dull-looking Log Parser charts.

Note: This blog was originally posted at http://blogs.msdn.com/robert_mcmurray/
Posted: Aug 24 2012, 18:53 by Bob | Comments (0)
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: LogParser | Scripting
Social Bookmarks: E-mail | Kick it! | DZone it! | del.icio.us

Windows Cache 1.3 for PHP 5.4

The IIS team has officially signed off on the Windows Cache Extension (WinCache) version 1.3 for PHP 5.4, and the files have been uploaded to SourceForge. This version addresses all of the problems that were identified with WinCache 1.1 that customers were seeing after they upgraded their systems from PHP 5.3 to PHP 5.4.

With that in mind, you can download WinCache 1.3 for for PHP 5.4 from the following URL:

http://sourceforge.net/projects/wincache/files/wincache-1.3.4/

You can discuss WinCache 1.1 and WinCache 1.3 in the Windows Cache Extension for PHP forum on Microsoft's IIS.net website.

Source Code Availability

Since WinCache is an open source project, the IIS team has uploaded the pre-release source code for WinCache at the following URL:

http://pecl.php.net/package/WinCache

For the instructions on how to build the extension yourself, please refer to the Building WinCache Extension documentation.

Note: This blog was originally posted at http://blogs.msdn.com/robert_mcmurray/
Posted: Jul 26 2012, 05:37 by Bob | Comments (0)
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: IIS | PHP | WinCache
Social Bookmarks: E-mail | Kick it! | DZone it! | del.icio.us

WebDAV Website Importer for WebMatrix

The other day I was talking with one of my coworkers, Yishai Galatzer, about Microsoft's WebMatrix. By way of introduction, Yishai is one of our senior developers on the WebMatrix project; I'm not sure if you've used WebMatrix, but it's a pretty handy website editor. Here's a few generic screen shots:

WebMatrix 2 Splash Screen
WebMatrix 2 Quick Start Screen
Editing QDIG in WebMatrix 2

In any event, I was explaining how easy it is to work with WebDAV, and I mentioned that I had written some some blogs about working with WebDAV websites programmatically. (See my Sending WebDAV Requests in .NET Revisited blog for an example.) Since WebMatrix 2 has some pretty cool extensibility, Yishai challenged me to write a WebDAV extension for WebMatrix. His idea was just too good for me to pass up, so I stayed up late that night and I wrote a simple WebDAV Website Import extension for WebMatrix 2.

With that in mind, there are a few things that I need to explain in this blog:

  • What this extension actually does.
  • How to install this extension.
  • How to use this extension.

What the WebDAV Website Importer Extension Actually Does

The WebDAV Website Importer extension does just what its name implies - it allows you to import a website into WebMatrix over WebDAV. This allows you to download your website to your local computer, where you can make changes to your source files and test them on your local system with IIS Express.

It should be noted that this extension is only designed to create a new local website by downloading a copy of your website's files in order to create a local copy of your website - it is not designed to be a website publishing feature like WebMatrix's built-in FTP and Web Deploy features. (I would like to write a full-featured website import/export/sync extension, but that's another project for another day.)

How to Install the WebDAV Website Importer Extension

To install this extension, you first need to install WebMatrix. You can find details about installing WebMatrix at the following URL:

Once you have WebMatrix installed, click the Extensions menu on the ribbon, and then click Gallery.

WebMatrix 2's Extensions Menu

When the Extensions Gallery appears, you will see the WebDAV Website Importer in the list of extensions.

WebDAV Website Importer in the Extensions List

When you click Install, the WebDAV Website Importer details page will be displayed.

WebDAV Website Importer Details

When you click Install, the End User License Agreement for the WebDAV Website Importer will be displayed.

WebDAV Website Importer EULA

When you click I Accept, WebMatrix will download and install the extension.

How to Use the WebDAV Website Importer Extension

Once you have downloaded and installed the WebDAV Website Importer extension, it will show up whenever you are creating a new website in WebMatrix.

Import Site from WebDAV menu

When you click Import Site from WebDAV, WebMatrix will prompt you for the credentials to your WebDAV website.

WebDAV Website Credentials Dialog

Once you enter your credentials and click OK, the extension will import the content from your WebDAV website and save it in a new local website folder.

Summary

So - there you have it; this is a pretty simple extension, but it opens up some WebDAV possibilities for WebMatrix. As I mentioned earlier, this extension is import-only - perhaps I'll write a full-featured import/export/sync extension in the future, but for now - this was a cool test for combining WebMatrix extensibility and WebDAV.

Note: This blog was originally posted at http://blogs.msdn.com/robert_mcmurray/
Posted: Jul 20 2012, 18:12 by Bob | Comments (0)
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: WebDAV | WebMatrix
Social Bookmarks: E-mail | Kick it! | DZone it! | del.icio.us

Creating "Pretty" XML using XSL and VBScript

I was working with an application recently that stored all of its settings in a large XML file, however, when I opened the XML in Windows Notepad, all I saw was a large blob of tags and text - there was no structured formatting to the XML, and that made it very difficult to change some of settings by hand. (Okay - I realize that some of you are probably thinking to yourselves, maybe I wasn't supposed to be editing those settings by hand - but that's just the way I do things around here... if I can't customize every setting to my heart's content, then it's just not worth using.)

In any event, I'll give you an example of what I mean by using the example XML database that's provided on MSDN at the following URL:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms762271.aspx

Note - the entire XML file would be too long to repost here, so I'll just include an unstructured except from that file that resembles what my other XML looked like when I opened the file in Windows Notepad:

<?xml version="1.0"?><catalog><book id="bk101"><author>Gambardella, Matthew</author><title>XML Developer's Guide</title><genre>Computer</genre><price>44.95</price><publish_date>2000-10-01</publish_date><description>An in-depth look at creating applications with XML.</description></book><book id="bk102"><author>Ralls, Kim</author><title>Midnight Rain</title><genre>Fantasy</genre><price>5.95</price><publish_date>2000-12-16</publish_date><description>A former architect battles corporate zombies, an evil sorceress, and her own childhood to become queen of the world.</description></book><book id="bk103"><author>Corets, Eva</author><title>Maeve Ascendant</title><genre>Fantasy</genre><price>5.95</price><publish_date>2000-11-17</publish_date><description>After the collapse of a nanotechnology society in England, the young survivors lay the foundation for a new society.</description></book></catalog>

This is obviously difficult to read, and even more so when you are dealing with hundreds or thousands of lines of XML code. What would be considerably easier to read and edit would be something more like the following example:

<?xml version="1.0"?>
<catalog>
  <book id="bk101">
    <author>Gambardella, Matthew</author>
    <title>XML Developer's Guide</title>
    <genre>Computer</genre>
    <price>44.95</price>
    <publish_date>2000-10-01</publish_date>
    <description>An in-depth look at creating applications with XML.</description>
  </book>
  <book id="bk102">
    <author>Ralls, Kim</author>
    <title>Midnight Rain</title>
    <genre>Fantasy</genre>
    <price>5.95</price>
    <publish_date>2000-12-16</publish_date>
    <description>A former architect battles corporate zombies, an evil sorceress, and her own childhood to become queen of the world.</description>
  </book>
  <book id="bk103">
    <author>Corets, Eva</author>
    <title>Maeve Ascendant</title>
    <genre>Fantasy</genre>
    <price>5.95</price>
    <publish_date>2000-11-17</publish_date>
    <description>After the collapse of a nanotechnology society in England, the young survivors lay the foundation for a new society.</description>
  </book>
</catalog>

I had written a "Pretty XML" script sometime around ten years ago that read an XML file, collapsed all of the whitespace between tags, and then inserted CRLF sequences and TAB characters in order to reformat the file. This script worked great for many years, but I decided that it would be more advantageous to use XSL to transform the XML. (e.g. "Why continue to do things the hard way when you really don't need to?");-]

With that in mind, I rewrote my old script as the following example:

' ****************************************
' MAKE PRETTY XML
' ****************************************

Option Explicit

Const strInputFile = "InputFile.xml"
Const strOutputFile = "OutputFile.xml"

' ****************************************

Dim objInputFile, objOutputFile, strXML
Dim objFSO : Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
Dim objXML : Set objXML = WScript.CreateObject("Msxml2.DOMDocument")
Dim objXSL : Set objXSL = WScript.CreateObject("Msxml2.DOMDocument")

' ****************************************
' Put whitespace between tags. (Required for XSL transformation.)
' ****************************************

Set objInputFile = objFSO.OpenTextFile(strInputFile,1,False,-2)
Set objOutputFile = objFSO.CreateTextFile(strOutputFile,True,False)
strXML = objInputFile.ReadAll
strXML = Replace(strXML,"><",">" & vbCrLf & "<")
objOutputFile.Write strXML
objInputFile.Close
objOutputFile.Close

' ****************************************
' Create an XSL stylesheet for transformation.
' ****************************************

Dim strStylesheet : strStylesheet = _
"<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform"">" & _
"<xsl:output method=""xml"" indent=""yes""/>" & _
"<xsl:template match=""/"">" & _
"<xsl:copy-of select="".""/>" & _
"</xsl:template>" & _
"</xsl:stylesheet>"

' ****************************************
' Transform the XML.
' ****************************************

objXSL.loadXML strStylesheet
objXML.load strOutputFile
objXML.transformNode objXSL
objXML.save strOutputFile

WScript.Quit

This script is really straightforward in what it does:

  1. Creates two MSXML DOM Document objects:
    • One for XML
    • One for XSL
  2. Creates two file objects:
    • One for the input/source XML file
    • One for the output/destination XML
  3. Reads all of the source XML from the input file.
  4. Inserts whitespace between all of the XML tags in the source XML; this is required or the XSL transformation will not work properly.
  5. Saves the resulting XML into the output XML file.
  6. Dynamically creates a simple XSL file that will be used for transformation in one of the MSXML DOM Document objects.
  7. Loads the output XML file from earlier into the other MSXML DOM Document object.
  8. Transforms the source XML into well-formatted ("pretty") XML.
  9. Replaces the XML in the output file with the transformed XML.

That's all that there is to it.

Note: For more information about the XSL stylesheet that I used, see http://www.w3.org/TR/xslt.

Note: This blog was originally posted at http://blogs.msdn.com/robert_mcmurray/

Posted: Jul 06 2012, 06:07 by Bob | Comments (0)
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: Scripting | XML
Tags: , ,
Social Bookmarks: E-mail | Kick it! | DZone it! | del.icio.us

Working with the Different IIS Express Modes and HTTPS

I had another great question from a customer the other day, and I thought that his question was the perfect impetus for me to write blog that explained the different modes of IIS Express.

The customer's issue was that he was trying to run IIS Express from a command-line by specifying the path to a folder and he wanted to use that with SSL. He couldn't find a way to accomplish that, so he asked Scott Hanselman if there was a switch that he was missing, and Scott sent him my way. In the meantime, he was copying one of the IIS Express template ApplicationHost.config files and configuring SSL by modifying the XML programmatically.

First of all, the short answer is that there isn't some form of "/https" switch for IIS Express that the customer was asking about.

But that being said, this seemed like a great occasion for me to explain a little bit of design architecture for IIS Express, which might help everyone understand a little bit about what's going on behind the scenes when you run IIS Express.

In case you weren't aware, there are actually two modes that you can use with IIS Express:

  • Personal Web Server Mode
  • Application Server Mode

Having said that, I'll explain what both of those fancy titles actually mean, and how you can use IIS Express with SSL.

Personal Web Server Mode

When you are using Personal Web Server Mode, one ApplicationHost.config file is created per user by default, (unless an alternate file is specified on the command-line), and by default that ApplicationHost.config file is kept in your "%UserProfile%\Documents\IISExpress\config" folder.

In this mode, websites are persistent like they are with the full version of IIS, and the template that is used to create the per-user ApplicationHost.config file is located at:

"%ProgramFiles%\IIS Express\config\templates\PersonalWebServer\ApplicationHost.config"

Note: When you are using Personal Web Server Mode, your default website is named "WebSite1".

The general syntax for Personal Web Server Mode is:

iisexpress.exe [/config:config-file] [/site:site-name] [/systray:true|false] [/siteid:site-id] [/userhome:user-home]

If you are using IIS Express from a command-line with no parameters, or you are using IIS Express with WebMatrix or Visual Studio, then you are using Personal Web Server Mode. You can use SSL by enabling HTTPS in either WebMatrix or Visual Studio, or you can modify your ApplicationHost.config file directly and add an HTTPS binding to a website.

Application Server Mode

When you are using "Application Server Mode," a temporary ApplicationHost.config file generated when IIS Express starts in the user's "%TEMP%\iisexpress" folder.

In this mode, sites are transient like they are with Cassini, and the template that is used to create the temporary ApplicationHost.config file is located at:

"%ProgramFiles%\IIS Express\AppServer\ApplicationHost.config"

Note: When you are using Application Server Mode, your default website is named "Development Web Site".

The general syntax for Application Server Mode is:

iisexpress.exe /path:app-path [/port:port-number] [/clr:clr-version] [/systray:true|false]

If you are using IIS Express from a command-line by specifying the path to a folder, then you are using Application Server Mode, and unfortunately you can't use SSL with this mode.

Using SSL with IIS Express

As I have already mentioned, if you are using Personal Web Server Mode, you can use SSL by enabling HTTPS in WebMatrix or Visual Studio if you are using either of those tools, or you can modify your ApplicationHost.config file directly and add an HTTPS binding to a website.

However, there is no way to specify HTTPS for Application Server Mode; but that being said, there are definitely workarounds that you can use.

Copying the template file like the customer was doing is a good place to start. But I need to state an important warning: you should never modify the actual template files that are installed with IIS Express! However, if you copy the template files somewhere else on your system, you can modify the copied files as much as you want.

If you are using IIS 8 Express, we've made it possible to use AppCmd.exe with any ApplicationHost.config file by using the "/apphostconfig" switch. So instead of modifying the XML directly, you can use AppCmd.exe to make your changes for you.

For example, the following batch file creates a temporary website and sets it up for use with HTTPS:

@echo off

pushd "%~dp0"

REM Create the website's folders.

md %SystemDrive%\myhttpstemp
md %SystemDrive%\myhttpstemp\wwwroot
md %SystemDrive%\myhttpstemp\config

REM Copy the template configuration file.

copy "%ProgramFiles%\IIS Express\AppServer\ApplicationHost.config" %SystemDrive%\myhttpstemp\config

REM Configure the website's home directory.

"%ProgramFiles%\IIS Express\appcmd.exe" set config -section:system.ApplicationHost/sites /"[name='Development Web Site'].[path='/'].[path='/'].physicalPath:%SystemDrive%\myhttpstemp\wwwroot" /commit:apphost /apphostconfig:%SystemDrive%\myhttpstemp\config\ApplicationHost.config

REM Configure the website for SSL.

"%ProgramFiles%\IIS Express\appcmd.exe" set config -section:system.ApplicationHost/sites /+"[name='Development Web Site'].bindings.[protocol='https',bindingInformation='127.0.0.1:8443:']" /commit:apphost /apphostconfig:%SystemDrive%\myhttpstemp\config\ApplicationHost.config

REM Enable directory browsing so this example works without a home page.

"%ProgramFiles%\IIS Express\appcmd.exe" set config "Development Web Site" -section:system.webServer/directoryBrowse /enabled:"True" /commit:apphost /apphostconfig:%SystemDrive%\myhttpstemp\config\ApplicationHost.config

REM Run the website with IIS Express.

"%ProgramFiles%\IIS Express\iisexpress.exe" /config:%SystemDrive%\myhttpstemp\config\ApplicationHost.config /siteid:1 /systray:false

REM Clean up the website folders.

rd /q /s %SystemDrive%\myhttpstemp

popd

As you can see in the above example, this is a little more involved than simply invoking Application Server Mode with a switch to enable HTTPS, but it's still very easy to do. The changes that we've made in IIS 8 Express make it easy to script Personal Web Server Mode in order to enable SSL for a temporary website.

In Closing...

I hope this information makes using the various IIS Express modes and SSL a little clearer, and you can get IIS 8 Express by following the link in the following blog post:

http://blogs.msdn.com/b/robert_mcmurray/archive/2012/05/31/microsoft-iis-8-0-express-release-candidate-is-released.aspx

Note: This blog was originally posted at http://blogs.msdn.com/robert_mcmurray/

Posted: Jul 03 2012, 07:06 by Bob | Comments (0)
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: IIS Express | Scripting
Social Bookmarks: E-mail | Kick it! | DZone it! | del.icio.us

Error: Class Not Registered (0x80040154) when Querying FTP Runtime State

I had a great question from a customer earlier today, and I thought that it was worth blogging about. The problem that he was running into was that he was seeing the following error when he was trying to query the runtime state for the FTP service in an application that he was writing:

Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG))

He was using Visual Basic, and his code looked okay to me, so for the moment I was stumped.

I'm more of a C# guy, and I remembered that I had written the following blog many years ago:

Viewing current FTP7 sessions using C#

I copied the code from that blog into a new Visual Studio project, and I got the same error that he was seeing when I ran my code - this had me a little more confused. Have you ever said to yourself, "Darn - I know that worked the other day...?" ;-]

I knew that there is more than one way to access the runtime state, so I rewrote my sample application using two different approaches:

Method #1:

AppHostAdminManager objAdminManager = new AppHostAdminManager();
IAppHostElement objSitesElement =
  objAdminManager.GetAdminSection("system.applicationHost/sites",
  "MACHINE/WEBROOT/APPHOST");
uint intSiteCount = objSitesElement.Collection.Count;
for (int intSite = 0; intSite < intSiteCount; ++intSite)
{
    IAppHostElement objFtpSite = objSitesElement.Collection[intSite];
    Console.WriteLine("Name: " + objFtpSite.Properties["name"].StringValue);
    IAppHostElement objFtpSiteElement = objFtpSite.ChildElements["ftpServer"];
    IAppHostPropertyCollection objProperties = objFtpSiteElement.Properties;
    try
    {
        IAppHostProperty objState = objProperties["state"];
        string ftpState = objState.StringValue;
        Console.WriteLine("State: " + ftpState);
    }
    catch (System.Exception ex)
    {
        Console.WriteLine("\r\nError: {0}", ex.Message);
    }
}

Method #2:

ServerManager manager = new ServerManager();
foreach (Site site in manager.Sites)
{
    Console.WriteLine("Name: " + site.Name);
    ConfigurationElement ftpServer = site.GetChildElement("ftpServer");
    try
    {
        foreach (ConfigurationAttribute attrib in ftpServer.Attributes)
        {
            Console.WriteLine(attrib.Name + ": " + attrib.Value);
        }
    }
    catch (System.Exception ex)
    {
        Console.WriteLine("\r\nError: {0}", ex.Message);
    }
}

Both of these methods returned the same COM error, so this was getting weird for me. Hmm...

The FTP runtime state is exposed through a COM interface, and that is implemented in a DLL that is named "ftpconfigext.dll". That file should be registered when you install IIS, and I re-registered it on my system just for good measure, but that didn't resolve the issue.

I had a brief conversation with one of my coworkers, Eok Kim, about the error that I was seeing. He also suggested re-registering the DLL, but something else that he said about searching the registry for the InprocServer32 entry made me wonder if the whole problem was related to the bitness of my application.

To make a long story short - that was the whole problem.

Both the customer and I were creating 32-bit .NET applications, and the COM interface for the FTP runtime state is implemented in a 64-bit-only DLL. Once we both changed our projects to compile for 64-bit platforms, we were both able to get the code to run. (Coincidentally, all I had was a 32-bit system when I wrote my original blog, so I probably would have run into this sooner if I had owned a 64-bit system way back then. ;-])

Note: This blog was originally posted at http://blogs.msdn.com/robert_mcmurray/

Posted: Jun 29 2012, 12:01 by Bob | Comments (0)
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: FTP | IIS
Social Bookmarks: E-mail | Kick it! | DZone it! | del.icio.us

Using URL Rewrite with QDIG

One of the applications that I like to use on my websites it the Quick Digital Image Gallery (QDIG), which is a simple PHP-based image gallery that has just enough features to be really useful without a lot of work on my part to get it working. (Simple is always better - ;-].) Here's a screenshot of QDIG in action with some Bing photos:

(Click to enlarge photo.)

The trouble is, QDIG creates some really heinous query string lines; see the URL line in the following screenshot for an example:

(Click to enlarge photo.)

I don't know about you, but in today's SEO-friendly world, I hate long and convoluted query strings. Which brings me to one of my favorite subjects: URL Rewrite for IIS

If you've been around IIS for a while, you probably already know that there are a lot of great things that you can do with the IIS URL Rewrite module, and one of the things that URL Rewrite is great at is cleaning up complex query strings into something that's a little more intuitive.

It would take way to long to describe all of the steps to create the following rules with the URL Rewrite interface, so I'll just include the contents of my web.config file for my QDIG directory - which is a physical folder called "QDIG" that is under the root of my website:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <!-- Rewrite the inbound URLs into the correct query string. -->
        <rule name="RewriteInboundQdigURLs"  stopProcessing="true">
          <match url="Qif/(.*)/Qiv/(.*)/Qis/(.*)/Qwd/(.*)" />
          <conditions>
            <add input="{REQUEST_FILENAME}"  matchType="IsFile" negate="true" />
            <add input="{REQUEST_FILENAME}"  matchType="IsDirectory" negate="true" />
          </conditions>
          <action type="Rewrite"  url="/QDIG/?Qif={R:1}&amp;Qiv={R:2}&amp;Qis={R:3}&amp;Qwd={R:4}"  appendQueryString="false" />
        </rule>
      </rules>
      <outboundRules>
        <!-- Rewrite the outbound URLs into user-friendly URLs. -->
        <rule name="RewriteOutboundQdigURLs"  preCondition="ResponseIsHTML"  enabled="true">
          <match filterByTags="A, Img, Link"  pattern="^(.*)\?Qwd=([^=&amp;]+)&amp;(?:amp;)?Qif=([^=&amp;]+)&amp;(?:amp;)?Qiv=([^=&amp;]+)&amp;(?:amp;)?Qis=([^=&amp;]+)(.*)" />
          <action type="Rewrite"  value="/QDIG/Qif/{R:3}/Qiv/{R:4}/Qis/{R:5}/Qwd/{R:2}" />
        </rule>
        <!-- Rewrite the outbound relative QDIG URLs for the correct path. -->
        <rule name="RewriteOutboundRelativeQdigFileURLs"  preCondition="ResponseIsHTML"  enabled="true">
          <match filterByTags="Img"  pattern="^\.\/qdig-files/(.*)$" />
          <action type="Rewrite"  value="/QDIG/qdig-files/{R:1}" />
        </rule>
        <!-- Rewrite the outbound relative file URLs for the correct path. -->
        <rule name="RewriteOutboundRelativeFileURLs"  preCondition="ResponseIsHTML"  enabled="true">
          <match filterByTags="Img"  pattern="^\.\/(.*)$" />
          <action type="Rewrite"  value="/QDIG/{R:1}" />
        </rule>
        <preConditions>
          <!-- Define a precondition so the outbound rules only apply to HTML responses. -->
          <preCondition name="ResponseIsHTML">
            <add input="{RESPONSE_CONTENT_TYPE}"  pattern="^text/html" />
          </preCondition>
        </preConditions>
      </outboundRules>
    </rewrite>
  </system.webServer>
</configuration>

Here's the breakdown of what all of the rules do:

  • RewriteInboundQdigURLs - This rule will rewrite inbound user-friendly URLs into the appropriate query string values that QDIG expects. I should point out that I rearrange the parameters from the way that QDIG would normally define them; more specifically, I pass the value Qwd parameter last, and I do this so that the current directory "." does not get ignored by browsers and break the functionality.
  • RewriteOutboundQdigURLs - This rule will rewrite outbound HTML so that all anchor, link, and image tags are in the new format. This is where I actually rearrange the parameters that I mentioned earlier.
  • RewriteOutboundRelativeQdigFileURLs - There are several files that QDIG creates in the "/qdig-files/" folder of your application; when the application paths are rewritten, you need to make sure that the those paths won't just break. For example, once you have a path that is rewritten as http://localhost/QDIG/Qif/foo.jpg/Qiv/name/Qis/M/Qwd/, the relative paths will seem to be offset from that URL space as though it were a physical path; since it isn't, you'd get HTTP 404 errors throughout your application.
  • RewriteOutboundRelativeFileURLs - This rule is related to the previous rule, although this works for the files in your actual gallery. Since the paths are relative, you need to make sure that they will work in the rewritten URL namespace.
  • ResponseIsHTML - This pre-condition verifies if an outbound response is HTML; this is used by the three outbound rules to make sure that URL Rewrite doesn't try to rewrite responses where it's not warranted.

Once you have these rules in place, you get nice user-friendly URLs in QDIG:

(Click to enlarge photo.)

I should also point out that these rules also support changing the style from thumbnails to file names to file numbers, etc.

(Click to enlarge photo.)

All of that being said, there is one thing that these rules do not support - and that's nested folders under my QDIG application. I don't like to use folders under my QDIG folder - I like to use separate folders with the QDIG file in it, because this makes each gallery self-contained and easily transportable. That being said, after I had written the text for this blog, I tried to use a subfolder under my QDIG application and that didn't work. By looking at what was going on, I'm pretty sure that it would be pretty trivial to write some URL Rewrite rules that would accommodate using subfolders, but that's another project for another day. ;-]

Note: This blog was originally posted at http://blogs.msdn.com/robert_mcmurray/

Posted: Jun 28 2012, 13:10 by Bob | Comments (0)
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: IIS | URL Rewrite
Social Bookmarks: E-mail | Kick it! | DZone it! | del.icio.us

Microsoft IIS 8.0 Express Release Candidate is Released!

In addition to all of the other great products that Microsoft has released today, I’m happy to announce the release of the Internet Information Services (IIS) 8.0 Express Release Candidate. You can install the IIS 8.0 Express Release Candidate through the Microsoft Download Center by using the following URL:

http://go.microsoft.com/fwlink/?LinkId=254247

IIS 8.0 Express Release Candidate supports the following new features:

X64 Support
IIS 8.0 Express supports both 32-bit and 64-bit architectures.
Shared Features with IIS 8.0
IIS 8.0 Express shares a great number of features with the full version of IIS; for example, IIS 8.0 Express uses many of the same binaries, configuration files, and error codes as the full version of IIS, so migrating projects between your development environment and your production environment should be easier than ever.
Changing the User Home Directory
IIS 8.0 Express supports changing the user's home directory, which is mapped to the %IIS_USER_HOME% variable in configuration. By default this path is located at %UserProfile%\Documents\IISExpress, but users can change this by setting a CustomUserHome registry property in HKCU\Software\Microsoft\IISExpress, or by specifying the "/userhome" parameter when launching iisexpress.exe.
WebSocket Support
IIS 8.0 Express supports writing WebSocket applications. For more information, see the WebSocket protocol specification or the System.Net.WebSockets Namespace topic on Microsoft's MSDN website.
AppCmd Support for editing multiple configuration files
The AppCmd utility now supports a "/AppHostConfig" parameter, which makes it possible to use AppCmd to edit multiple ApplicationHost.config files and not just the primary configuration file.

For more information, see the IIS 8.0 Express ReadMe file.

My thanks to Eok Kim, Jeong Hwan Kim, Yamini Jagadeesan, Wade Hilmo, and Won Yoo!

Note: This blog was originally posted at http://blogs.msdn.com/robert_mcmurray/

Posted: May 31 2012, 11:29 by Bob | Comments (0)
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: IIS Express
Social Bookmarks: E-mail | Kick it! | DZone it! | del.icio.us