Archive for the ‘IIS’ Category

Migrating from DasBlog to WordPress

Due to many circumstances, I have a need to upgrade my shared hosting from .Net 3.5 to .Net 4.0. Normally this is no big deal, but I was running my blog on DasBlog, which hasn’t been officially updated since 2009, and it won’t just recompile and run under .Net 4. While there are some branches of their code re-compiled for .Net 4.0, I decided that un-tested code was not for me. I then decided on WordPress for a platform, mostly to continue expanding my horizons outside of Microsoft technology, and also because my hosting provider supports it, and I have more MySQL instances available for database use than SQL Server. I found an excellent post on migrating from DasBlog to WordPress, and used it mostly for a template on what I did, but since I did do some things differently, I decided to document my process. So below are the steps and technologies I utilized to migrate my blog.

Create a Test Environment

For my purposes, the first thing I did was create a Windows 7 virtual machine to do the migration testing. My production site is using shared hosting, so I can’t run a .exe on the server to get the content, which one of the tools I wanted to use required. I installed IIS, PHP, MySQL, and WordPress. I also made a new instance of WordPress in a virtual directory that matched the name of the virtual directory on my production WordPress install.

Set Up DasBlog Locally

I downloaded both the app files and the content from my hosting provider, then placed them in a virtual directory under IIS in my test environment, inside a virtual directory named to match the directory from production. I changed the site name in the DasBlog site.config file to reference the new location so the app would work.

Extract the DasBlog Content

I used DasBlogML to extract the data from DasBlog on the local instance of DasBlog, which outputs a blogML XML file. Some articles imply you need to remove any non-breaking spaces (   ) from the resulting XML, but I didn’t and had no issues.

Import the Data

I added the BlogML Importer plug-in to both my local install of WordPress and my production instance. I used that plug-in from the test instance to import the data and examine the results. For me it worked without issues, bringing over all the posts, comments, and categories. I had about 160 posts to migrate.

Create A WordPress theme

I am still enamored with the current look and feel of my blog which I built for myself as a DasBlog theme. I decided to migrate that HTML layout into a new WordPress theme, instead of using one of the myriad of available themes. I started with the HTLM5 Reset WordPress theme as a base and added the HTML structure and CSS from my DasBlog theme. I ended up modifying quite a few files in the theme in order to get it to work, and getting accustomed to PHP along the way.

Migrate Data and new theme to Production

I zipped up the WordPress theme directory on my test machine, and uploaded it as a theme in my production WordPress instance. Then I migrated the data using the BlogML Importer plug-in. I also had to configure the widgets in the navigation area and manually migrate some data into them.

Redirection

This is where the real work for the migration begins. Since my blog has existed since 2003, I wanted to maintain my links in search engines as much as possible. I already lost this once when DotNetJunkies (where I began to blog originally) got closed down by Dr. Dobbs, and it killed my comment traffic going forward. The post by Andreas that I was following advocated writing your own Http Module in .Net to handle all the redirects. I initially thought that was the way to go, but I found out that my hosting provider has the URL Rewriting feature installed for IIS7, so I could use the config file route. I figured that would perform better than any code I would write and is likely less buggy, even though over time the code should be used less and less. It also let me handle some of the one-off pages I added on the site that looked like part of DasBlog but really were just static HTML files, as well as some other media content.

There are a number of type of pages that DasBlog uses that need redirect templates:

  • Permalink
  • Permalink by Guid
  • Categories
  • Dates
  • CommentView

DasBlogML also generated a CSV file matching up the DasBlog permalinks with the WordPress permalinks. I used that as a starting point, and also queried the blogML XML file for the guids and dates of each post, and then matched them up with the CSV file in Excel.  I then used simple formulas in Excel to generate the XML needed for a static re-write file. Because the number of rewrites is so numerous, I decided to store the mappings in an external file called “maps.config” and reference that from web.config. The basic structure (one example per type) of maps.config is:

  1. <rewriteMaps>
  2.   <rewriteMap name="StaticRedirect">
  3.     
  4.     <!– Permalink –>
  5.     <add key="/blog/2011/12/16/AndroidAVDProblem.aspx" value="/2011/12/16/android-avd-problem/"/>
  6.     <!– Category –>
  7.     <add key="/blog/CategoryView,category,Mobile.aspx" value="/category/mobile/"/>
  8.     <!– Permalink by guid –>
  9.     <add key="/blog/PermaLink,guid,d280262b-e81e-496b-abde-453b6381574f.aspx" value="/2011/12/16/android-avd-problem/"/>
  10.     <!– Comment View –>
  11.     <add key="/blog/CommentView,guid,d280262b-e81e-496b-abde-453b6381574f.aspx" value="/2011/12/16/android-avd-problem/"/>
  12.     <!– Track back –>
  13.     <add key="/blog/Trackback.aspx?guid=d280262b-e81e-496b-abde-453b6381574f" value="/2011/12/16/android-avd-problem/trackback/"/>
  14.     <!– Date –>
  15.     <add key= "/blog/default,data,2010-01-04.aspx " value= "/2011/12/"/>
  16.     
  17.   </rewriteMap>
  18. </rewriteMaps>

And in web.config of the DasBlog virtual directory I added the following section:

  1. <system.webServer>
  2.     <rewrite>
  3.       <rewriteMaps configSource="maps.config"/>
  4.            <rules>
  5.           <rule name="RedirectRule" stopProcessing="True">
  6.               <match url=".*" />
  7.               <conditions>
  8.                     <add input="{StaticRedirect:{URL}}" pattern="(.+)" />
  9.               </conditions>
  10.               <action type="Redirect" url="http://localhost/wp{C:1}" redirectType="Permanent" />
  11.           </rule>
  12.       </rules>
  13.     </rewrite>
  14. </system.webServer>

To get it to take effect I had to recycle the app pool of the DasBlog app. The important part of the rule is the action. By setting the redirectType to Permanent, it causes IIS to issue a 301 response for the redirect, which tells the caller this is a permanent change. So any search engine should re-write the link in their database and not start you all over again in search engine results. And any other links outside of your site will just redirect automatically.

At this point it seems the new blog is running fine and the redirects are all working. I left the DasBlog instance running, at least for a while. I’m keeping my eye on Google Analytics to see if any other hits show up on the old blog. I am not an expert as DasBlog, so if any other page types show up I’ll find out about it and fix it in the redirect file.

Posted on:
Posted in IIS, Strange Problems, Tools | Comments Off on Migrating from DasBlog to WordPress

Day of .Net Slides

I posted my slide deck from my talk (The Demise of Xcopy Deployment) at the terrific Ann Arbor Day of .Net 2010 on SlideShare. Thanks to everyone who attended both my talk and the event. A special thanks to the event organizers for doing a great job.

MSDeploy Resources

Blogs

The Microsoft Web Deployment Team Blog on IIS.net

Owais Shaikh’s Blog on IIS.net

Kristina Olson’s Blog

James Cook’s Blog

Kateryna Rohonyan’s Blog

Articles

How does Web Deployment with VS10 and MSDeploy Work?

Web Packaging: Creating web packages using MSBuild

Web Packaging: Installing Web Packages using Command Line

SQLCMD scripts in Web Deploy (MSDeploy) v1.1

ASP.NET Deployment Content Map

Visual Web Developer Team Blog

MS Deploy Basics

How To Use MSDeploy to Migrate Global Assembly Cache

How We Practice Continuous Integration And Deployment With MSDeploy

Getting MSDeploy working on our build/integration server

Using MSDeploy as a build task in TFS

Posted on:
Posted in IIS, MSDeploy, Tools | Comments Off on MSDeploy Resources

Setting up MSDeploy on a Development Server

It’s not enough to just install MSDeploy on a server to allow Visual Studio 2010 to connect to the server. If you don’t follow the steps below, you will probably get 403 errors when trying to connect.

  1. When adding the Web Server (IIS) role, be sure to install Management Service.
  2. In the Services snap-in, find the Web Management Service and set its startup to Automatic (it’s manual by default). Don’t start it yet.
  3. Open the Internet Information Services Manager, and select the server.
  4. Open the Management Service feature.
  5. Check Enable Remote Connections.
  6. Choose a port (or keep the default), IP, Certificate, choose any restrictions you might require.
  7. In the Actions part of the right pane, click Apply.
  8. Click the Start link in the right pane.

Now IIS is configured to accept incoming connections. Open a port on the firewall for the port (8172 by default) you selected in step 6 above.

Install MSDeploy. Make sure you start the Web Deployment Service after the install, and set the service startup to Automatic.

Now you can use the Publish feature of Visual Studio 2010 to push directly to your development server.

See also: http://msdn.microsoft.com/en-us/library/dd465337.aspx

Posted on:
Posted in IIS, MSDeploy, Tools, Visual Studio | Comments Off on Setting up MSDeploy on a Development Server

Ann Arbor Day of .Net 2010

I’ll be speaking at the Ann Arbor Day of .Net on Saturday, May 1st, 2010. It’s being held at Washtenaw Community College. Register for the event at http://www.dayofdotnet.org/AnnArbor/Spring2010/Registration.aspx 

Here’s the abstract for my talk:

The Demise of Xcopy Deployment

One of the great features of .Net when it first released was Xcopy deployment. No more .dll registrations, just copy the files to the web server. While this was a great feature for Microsoft developers, new problems emerged, specifically around managing web.config. Sections like connection strings and custom errors need to be managed between environments, which meant many copies of the files or scripts to change them. Other necessary steps, like managing permissions and IIS configuration were still outside the Xcopy process. A recent tool, MSDeploy, is now integrated into Visual Studio 2010 and makes managing these issues easier. Besides web.config, MSDeploy also manages file deployments and synchronization, ACLs, and IIS settings. If your deployments have multiple steps, need ReadMe files, or can’t be done by someone outside your team, you need to learn MSDeploy!

Useful LogParser Queries

If you deal with production servers and you don’t use LogParser, you should. It gives SQL-like abilities to query web server logs an other log types (like Event Logs). Coding Horror has a great article about the tool as well, and a link to a good article about forensic log parsing. Here are my most used web queries:

Find Pages with 500 errors
logparser “SELECT cs-uri-stem as Url, sc-status as code, COUNT(cs-uri-stem) AS Hits FROM C:\ProdLogFiles\ex*.log WHERE (sc-status >= 500) GROUP BY cs-uri-stem, code ORDER BY Hits DESC” -o:CSV >> C:\Data\ErrorPages.csv

Find 404 Requests
logparser “SELECT cs-uri-stem as Url, sc-status as code, COUNT(cs-uri-stem) AS Hits FROM C:\ProdLogFiles\ex*.log WHERE (sc-status = 404) GROUP BY cs-uri-stem, code ORDER BY Hits DESC” -o:CSV >> C:\Data\404Pages.csv

Find the Slowest Pages
logparser “SELECT TOP 100 cs-uri-stem AS Url, MIN(time-taken) as [Min], AVG(time-taken) AS [Avg], max(time-taken) AS [Max], count(time-taken) AS Hits FROM C:\ProdLogFiles\ex*.log GROUP BY Url ORDER BY [Avg] DESC” -o:CSV >> C:\Data\SlowPages.csv

ASP.NET 404 Errors on the Default.aspx Page

On a new server install, you can copy over the files for your web app and mysteriously get 404 errors. It’s a simple configuration in IIS. By default the server is configured not to allow ASP.NET. You simply need to enable this in the IIS management console:

Posted on:
Posted in ASP.NET, IIS | Comments Off on ASP.NET 404 Errors on the Default.aspx Page

Caching Images in IIS 6.0

Yahoo posted a list of rules for improving the performance of your web site, along with a new FireFox-based tool for diagnosing your site’s performance, called YSlow.

Their number one rule is to reduce the number of HTTP requests, and this only makes sense. I’ll bet most of us ASP.NET developers are well aware of output caching, and how to do this in code. But what about those static files, like images and scripts? Well, there is an IIS setting for that. It’s easy to do, and the payoff can be big if you have a very graphic-intense site. Here’s what you do for IIS 6:

  1. Open the IIS Management console
  2. Find the directory containing your images (static content only)
  3. Right click the directory, and choose Properties.
  4. Click the HTTP Headers tab.
  5. Check the Enable Content Expiration check box.
  6. Click the Expire After radio button, and choose an interval.
  7. Click the OK button. Done!

The downside is that you won’t get the payoff for the first time a user visits the site, but other pages using the same resources will be much snappier. Be aware that caching dynamically created content this way can cause some strange issues, so take care as to what you cache. As always, test it well before you release it and you will be rewarded.

Posted on:
Posted in IIS, Performance | Comments Off on Caching Images in IIS 6.0

Awesome IIS Resource

IISToolshed – thanks to Paschal for pointing it out.

Posted on:
Posted in IIS | Comments Off on Awesome IIS Resource

SelfSSL and Site ID

SelfSSL is a tool found in the IIS 6.0 Resource Kit. It allows you to generate SSL certificates for a development environment. In all the instructions for using SelfSSL, it describes one of the parameters as “Site ID”, where the default value=1, which is the default web site installed on the computer. The Site Id parameter is essentially telling SelfSSL which web site to install the certificate into. Well, if you have multiple web sites, then the default site id is useless. You need the Site Id of the web site where you want the certificate installed. Of course the documentation does not spell this out, and as a non-Admin the Site Id was not an intuitive term for me. But I found that there is a script you can run from the command-line called iisweb.vbs using the /query switch. That will tell you the Site Id. Seeing that, then I realized that the IIS log file folders (in windir\System32\logfiles\) are named according to the Site Id.

Anyway, creating a second certificate for a different site on the same IIS using SelfSSL messes up the SSL cert of first site. This is a known issue apparently, and David Wang has a great post on this problem. The comment further down by Paul Carrig is most useful, as he points out there is a workaround for the SelfSSL and multiple site issue. So I actually found two workarounds:

  1. The technique described by in the aforementioned post:
    1. Install the cert in the first site
    2. Export it to a .pfx file
    3. Install the cert in the second site
    4. Remove the cert from the first site
    5. Re-Import the cert to the first site using the .pfx file

      or

  2. Install the cert in the first site, and export it to a .pfx file. Then import that to the other sites. The down side to this is that the certificate is even less valid for the second sites as now it has an untrusted publisher (me!) and the site name is not a match. The prompt is essentially the same, but in our case one site contains web services which will throw an error if the prompt comes up at all (as it should). The workaround for that is to install the certificate on the client computers as well, which is an acceptable problem for a development enviroment.
Posted on:
Posted in IIS, Security | Comments Off on SelfSSL and Site ID