home · blog · groups · about us · contact us
DevelopmentNow Blog
 Monday, April 10, 2006
 
 

So after upgrading my XP Pro laptop to 2GB of RAM, I'm no longer able to hibernate it. Which stinks. I instead get the helpful "Insufficient System Resources Exist to Complete the API" error. And no, having lots of free disk space doesn't do anything.

Apparently it's a known issue, with an unsupported hotfix that you have to get by calling Microsoft. Thankfully, Owen Cutajar's UGH post contains a link to download the fix. Let's see if it works...

Edit: Seems to work! :)

OS
April 10, 2006    Bookmark to Digg or other social bookmarking
#    Disclaimer  |  Comments [2]



 
 

I was looking into ways to easily back up my local SQL Server database from the command line, and copy the resulting backup to my fileserver. That way I could kick off a backup manually or from a scheduled task. There are a few articles out there but they're more specific to SQL 2000 or earlier. Here's how to do it for SQL Server 2005.

I first made directory c:\sqlbackup and added a SQL script called backup.sql:

BACKUP DATABASE streamline TO DISK = 'c:\sqlbackup\streamline.bak' WITH INIT
GO
BACKUP LOG streamline TO DISK = 'c:\sqlbackup\streamline_log.bak' WITH INIT
GO

The above commands simply create log & database backups of the "streamline" database. I used the INIT parameter so that the backup files only create one version of the database (otherwise the backup files will grow & grow, containing every version of the database, each time you run a BACKUP command).

Then I made a simple batch file called backup.bat:

@echo off 
REM get today's date and time as one big string
for /f "tokens=2-4 delims=/ " %%i in ( 'date /t') do set theday=%%k%%i%%j
for /f "tokens=1-2 delims=: " %%i in ( 'time /t') do set thetime=%%i%%j
set now=%theday%%thetime%

REM create backup files
C:
cd "\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Binn"
sqlcmd -S localhost -U sa -P somepassword -i c:\sqlbackup\backup.sql -o c:\sqlbackup\log.txt

REM copy backup files to backup device
xcopy "C:\sqlbackup\*.*" \\10.1.10.50\ben_backup\sqlbackup\%now%\ /E /H /R 

The first section uses some DOS batch trickery to create a variable called %now% that contains the current day and time in the form of yyyymmddhhmm. The second section runs the backup script & writes the output to c:\sqlbackup\log.txt. The last section copies the all the backup files to my fileserver, inside a date & time specific folder. Notice how I used the %now% variable in the xcopy destination parameter.

Now my backup folder contains timestamped folders containing everything I need to restore my "streamline" database. You can use a similar technique to make file backups.

April 10, 2006    Bookmark to Digg or other social bookmarking
#    Disclaimer  |  Comments [0]



 Wednesday, March 29, 2006
 
 

The problem

When the number of computers in your house starts to grow, a file server starts looking more attractive. A place to back up all your important files, as well as store central files (e.g. virtual machines, tools, photos, mp3s) that are used by multiple machines. Sure, you can burn em to CD or DVD, but that's so slow, manual, and old school. Where exactly can you back up those files?

Option 1: Get a DAS (Direct Attached Storage)

AKA an external USB drive. USB enclosures are easy to get, and you can definitely store a lot of files on them. I have a few lying around, and you don't even need an external power brick for the 2.5" drive enclosures. I decided against them, though, since I needed to share files between multiple computers. 

Advantages:

  • Cheap
  • Very quick & easy to use
  • High transfer speed

Disadvantages:

  • Can't share files to multiple computers at the same time
  • Connecting to a different client involves unplugging, lugging, & plugging.

Option 2: Build a File Server

You could also build a full-fledged file server. Get a no-frills computer, load Linux or Windows on it, stick a bunch of drives in there, and share them across the LAN. I decided against this option for the time being since I wanted something cheap, easy, small, & quiet.

Advantages:

  • A file server can be used for other things, like a print server, mail server, web server, etc. Which can be fun, a source of geek pride, and educational.
  • Administration is via the server GUI, which you probably already know very well. And if you don't, it helps you build your resume. "Familiar with Windows Server administration" looks better than "Familiar with ECS EZ-NAS 2000."
  • Very good hardware support, including gigabit LAN
  • Support for RAID (software or hardware), so you can mirror two drives in case one fails
  • Advanced features like disk quotas, permissions, etc. You could also set up a WebDAV or FTP server to be able to access your files over the internet.

Disadvantages:

  • Cost: running a full OS (especially Windows 2003 or a fancy Linux GUI) can require more powerful hardware, meaning more money. More powerful machines also use more power.
  • Size: a normal server can be kinda bulky.
  • Time: installing & configuring an OS can take a while. It's not awful, but time is money!
  • Noise: a full server can be noisy, too, unless you spend more money making it quiet.

Option 3: Get a SAN (Storage Area Network)

I'm not really considering this due to the cost, although you can create a SAN using a file server (above) that implements iSCSI. There is a good (albiet a bit older) walkthrough for Linux and Windows here and of course Wikipedia has plenty of blurbage on it.

Option 4: Store Files Online

You could FTP all your important files to your ISP's server (or your server), or use your Gmail account like a hard drive, or use an online storage provider like Web 2.0 darling Box.net, collaboration tool Basecamp, or others. I use this method for sharing files with others, as offsite backup, and before travelling, but not as my main file storage.

Advantages:

  • No local equipment needed. You don't need to deal with hardware at all, which is attractive.
  • Cheap, even free for smaller amounts of files. Like if you're just backing up source code, documents, etc.
  • Access from anywhere, even on the road. If you have a net connection, you've got your file.
  • Reliable: in theory your ISP, Gmail, Basecamp, etc will have better backup & power systems than you do. So you don't need to worry (as much) about your files getting destroyed due to fire, hardware failure, etc.

Disavantages:

  • Slow, oh how slow. Basically as slow as your internet connection, which is probably 99% slower than your LAN. Which rules out videos and large files.
  • Not a lot of storage. This is relative, of course. 1-5gb might be plenty for some people, but not for others. Upgrading to more storage might either be expensive or not an option.
  • Out of your control. If the provider goes south, your files have, too.

Option 5: Get a NAS (Network Attached Storage)

This is the option I'm trying out. A NAS is basically external storage that you connect to your LAN. Your computers then access it over the network. You can always buy an enclosure for about $100 from NewEgg, etc (search on NAS), but I recently stumbled across NASLite and FreeNAS, embedded Linux kernels that turn an old PC (e.g. 200mhz!) into a NAS. Here is a very good and recent walkthough on FreeNAS, and here is a review on NASLite (plus a tip on making a 1.7mb floppy in order to boot NASLite). I'll post an update once I have either FreeNAS or NASLite running.

Advantages:

  • Inexpensive, especially if you already have an old PC lying around. If you don't, you can always buy one from the Salvation Army, Craigslist, or vendors like RetroBox.
  • Quiet: Old PCs don't need a lot of fans, and can often get away with passive cooling. The NAS units you buy are also pretty quiet.
  • Size: Old PCs aren't small, but the dedicated devices are. And some of them are even cute, leading to a better WAF.
  • Easy: Easy enough to get going.
  • Stability: A simpler device means fewer moving parts, as well as very little (if any) risk of that server getting infected with trojans and viruses. That doesn't mean that an infected client can't stick a virus-laden file onto the NAS, though, so make sure all your client PCs have antivirus (hint: Google Pack has a free 6-month Norton Antivirus).

Disadvantages:

  • Transfer speed: you're limited by the speed of your network and the amount of memory in the server. If you're running gigabit LAN, then it's decent, but if you're 100mbit or 10mbit, you'll start to notice transfer times for larger files compared to USB or Firewire. You can still stream mp3s & copy files around, but streaming video might be an issue for slower networks.
  • Size: Old PCs can be big.
  • Features: Cheaper NAS solutions don't offer RAID, which means if you lose the drive, your files are gone. FreeNAS does offer RAID, though, which is why I'm trying it first.

Conclusion

Hopefully the above helps you when considering storage solutions for your home network and important files. Keep an eye on DevelopmentNow for an update after my adventure with FreeNAS on a celeron 600.

March 29, 2006    Bookmark to Digg or other social bookmarking
#    Disclaimer  |  Comments [0]



 Thursday, March 23, 2006
 
 

A few weeks back I blogged about using UltraVNC for remote support. Since then I've used it a few times to troubleshoot problems for clients in Arizona, Chicago, etc and it works great. A picture truly is worth 1000 words. No more dialogues that go like this:

Client: I'm getting an error with the system.
Developer: What error message are you getting?
Client: I don't know, it's just blank.
Developer: Which part of the screen is blank?
Client: The system is blank, like I just said.
Developer: Hmm. Ok...can you send me a screenshot?
Client: How do I do that?
[5 minutes of screenshot tutorials go by, ending with the developer getting several blank emails but no actual screenshots]
Developer: Well, let's skip the screenshot for now. Can you go to the page with the error and copy and paste it into an email for me?
Client: Ok, here goes.
[a few minutes later, a blank email arrives in the developer's inbox]
Developer: That didn't come through, can you try selecting more of the system and pasting it into an email for me?
Client: *sigh* Ok, I'll try again. Here it comes.
[a few minutes later, an email containing the system's URL arrives in the developer's inbox]
Developer: Hmm. Can you just copy and paste the entire browser window into an email?
Client: Isn't that what I just did?

...and so on, ending in a frustrated client, an exasperated developer, a broken system, and world suffering. Of course, the issue will turn out to be an empty dropdown or something, which you could have found out in 10 seconds if you could actually see the client's computer screen.

So, if you have remote clients whose desktops you need to see for troubleshooting, software installation, diagnostics, & whatnot but you're too cheap to pay for WebEx, et al. you should check out UltraVNC SingleClick. I had some instructions in my previous blog post, but let me know if you want me to put up a step-by-step tutorial on setting it up.

March 23, 2006    Bookmark to Digg or other social bookmarking
#    Disclaimer  |  Comments [0]



 Wednesday, March 01, 2006
 
 

ASP.NET 2.0's new membership provider allows for three different ways to protect user's passwords via the passwordFormat attribute:

  • Clear: passwords are stored in clear text. Fine for non-sensitive applications.
  • Encrypted: passwords are encrypted. Note that you will have to put a hard-coded decryption key in the <machineKey> tag in your web.config or machine.config. Otherwise you'll get a "You must specify a non-autogenerated machine key to store passwords in the encrypted format" error when trying to create users. To create a machineKey tag with a set of random tags, you can use my machineKey generator (source code included).
  • Hashed: passwords are not stored in the database at all, only an SHA-1 hash. This means passwords can not be retrieved at all -- if a user forgets their password, they'll have to request a new, randomly-generated one.

Below is an example of a <membership> tag using the Encrypted password format.

        <membership defaultProvider="MySqlMembershipProvider" >
            <providers>
                <add name="MySqlMembershipProvider"
                connectionStringName="MyLocalSQLServer"
                applicationName="MyAppName"
                                 requiresUniqueEmail="false" enablePasswordRetrieval="true"
                                 enablePasswordReset="true" requiresQuestionAndAnswer="false"
                                 passwordFormat="Encrypted"
                                 minRequiredPasswordLength="4"
                                 minRequiredNonalphanumericCharacters="0"
                type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
            </providers>
        </membership>

March 1, 2006    Bookmark to Digg or other social bookmarking
#    Disclaimer  |  Comments [0]



 
 

I made some updates to the machineKey generation program I mentioned in my machineKey generation post. It now returns a complete machineKey tag for ASP.NET 1.1 or 2.0 that you can copy and paste into your web.config or machine.config. You can run the generator or download the code here.

March 1, 2006    Bookmark to Digg or other social bookmarking
#    Disclaimer  |  Comments [0]



 Thursday, February 16, 2006
 
 
Robert Scoble, blogger-under-notice from Microsoft, posted an interesting blurb about search ranking and secret blogger cliques. He suggested sticking the word brrreeeport in your blog to prove his point about tagging on Technorati.
February 16, 2006    Bookmark to Digg or other social bookmarking
#    Disclaimer  |  Comments [0]



 Wednesday, February 15, 2006
 
 

I was struggling for a while with how to get a profile of the queries being sent to MySQL. All my searches suggested running the debug version of MySQL, but it would either log WAY WAY too much information, or else not log the queries at all. I wanted something akin to the SQL Server Profiler, so I could just see the SQL and proc calls. Is that so much to ask? 

I eventually found the solution in the NHibernate forums (of all places), and it doesn't require running the debug version of MySQL at all. Inside your MySQL option file (e.g. "C:\Program Files\MySQL\MySQL Server 5.0\my.ini" or some other location), add the following line inside the [mysqld] section:

log="C:/Program Files/MySQL/MySQL Server 5.0/mysql.log"

Restart the MySQL service, and you'll get a nice log file continuously updated with all queries being sent to MySQL. You can view it with TextPad or some other text editor that can auto-refresh files when they change.

 

February 15, 2006    Bookmark to Digg or other social bookmarking
#    Disclaimer  |  Comments [0]



 
 

If you're getting the above error when loading your Visual Studio project, you should first ensure that the web server on your PC is running. Then confirm that .NET is installed by running "aspnet_regiis -i" in your windows\microsoft.net\framework\v1.1.4322 folder. Then open up Control Panel->Administrative Tools->Internet Information Services, and ensure the web site is running.

If you try to start the "Default Web Site" on your PC and get a strange error, make sure you don't have Skype running. It listens on port 80, preventing IIS from doing so. Which prevents your web projects from running in Visual Studio. :)

February 15, 2006    Bookmark to Digg or other social bookmarking
#    Disclaimer  |  Comments [0]



 
 

Like many developers, I've been intrigued by the hype around Ruby on Rails, but of course I don't have a Linux box handy and don't feel like setting up Apache, etc to try it out. What's a lazy programmer to do?

Enter Instant Rails, especially designed for Windows developers. From the description:

Instant Rails is a one-stop Rails runtime solution containing Ruby, Rails, Apache, and MySQL, all preconfigured and ready to run. No installer, you simply drop it into the directory of your choice and run it. It does not modify your system environment.

You can download Instant Rails here.

 

February 15, 2006    Bookmark to Digg or other social bookmarking
#    Disclaimer  |  Comments [0]



 Tuesday, February 14, 2006
 
 

On one of my projects, the client noted getting occasional errors when filling out forms. The errors were something like "Unable to validate data" or HttpException: Invalid_Viewstate. After some research, it turns out the error is due to the viewstate MAC (message authentication code) changing between postbacks, or more specifically, the viewstate MAC in the page is different than the MAC the server is expecting.

What is the ViewState MAC?

MAc stands for Message Authentication Code -- it's a way to ensure that messages haven't been tampered with.

As you know, the ViewState is ASP.NET's way of persisting form data across postbacks (John Peterson has a good overview if you want to know basic ViewState facts). This data appears in base-64 encoded form inside a hidden form value called __VIEWSTATE. The MAC is an additional value designed to prevent changing or tampering with viewstate data. ASP.NET looks at the data in the viewstate and, using a secret validation key, generates a hash from that data using SHA-1. That hash value is the MAC, and ASP.NET includes it in the form. When a postback occurs, your browser passes the form data, the viewstate, and the MAC value to the web server. ASP.NET looks at the submitted viewstate data and generates another MAC value on the fly. It then compares that MAC value to the MAC value contained in the POST information. If the two values match, then no one has tampered with the viewstate. If the newly-generated MAC doesn't match what comes across, however, then ASP.NET believes someone has monkeyed with the data in the viewstate and throws an Invalid_Viewstate error.

Why would the MAC be different from what the server expected?

Several things can cause the MAC to not match what ASP.NET is expecting:

  • Some hacker (maybe even you?) actually tried to change the data in the viewstate
  • The form data got cut off during submission to the server (due to timeout, crappy proxy server, etc)
  • Using Server.Transfer can cause it to happen
  • The validation key used to generate the previous MAC is different than the key being used to generate the new MAC

The last issue can happen more easily that you'd expect. One way is if you're running a web farm. By default, the validation key used to create the MAC is randomly generated by ASP.NET when the application pool starts up. This ensures that the validation key is unique and changes periodically. However, since the key is different from server to server, if you're viewing a page on Server A and post it to Server B, when Server B generates a MAC based on the viewstate data, that value won't match the MAC value when the page was initially served by Server A. Thus, you'll get an Invalid_Viewstate error.

Another reason the validation key (and thus the MAC) will be different is if you cross application pools. If you view a page running in pool A, and post to another page on pool B (e.g. through Server.Transfer), the key will be different & you'll get a mismatch.

Lastly, the validation  key can change mid-session for users if the application pool restarts. Assume some user is viewing a page on your site and filling out a form. While they're doing that, some sysadmin restarts the pool, thus generating a new key. When the user posts the page they'll get an Invalid_Viewstate error. The application can also restart if it is set to shut down while idle (the default is to shut down pools that have been idle for 20 minutes). Imagine a user who views a page on your site, goes away for 10 minutes then maybe spends 20 minutes filling in the form on the page. Meanwhile, no one else is on your site, so the application pool times out & shuts down. When the user finally posts the form (30 minutes after viewing it), the application pool will start back up, create a new validation key, generate a new MAC, notice that the MAC values don't match, and reward you user's diligence with an Invalid_Viewstate error.

Avoiding MAC Mismatch

There are a few ways to avoid MAC mismatch mishaps:

  1. Don't use the ViewState if you don't need to. Not only will it avoid the whole MAC issue, but your pages will run faster to boot.
  2. Turn off MAC generation by setting enableViewStateMac=false in the page or web.config. This isn't recommended, since the MAC helps prevent people from tampering with your viewstate data. But if tampering with viewstate data isn't a concern (and it may not be for some applications where there's no risk of fraud or security breaches), you can turn it off.
  3. Prevent your application pool from restarting by disabling the auto recycle and idle timeout settings in the application pool. This isn't a 100% guarantee that the pool won't restart, but it does help.
  4. Hard-code the MAC validation key so that it's always the same. I recommend this approach for web farms and/or if your application pool keep restarting for whatever reason (overzealous admins, memory leaks, etc). The biggest risk is now your key is hard-coded in a file, so you need to make sure your server is secure so that people don't get that key (otherwise they could hack your viewstate). You can hardcode the key in the <machineKey> tag in the machine.config or web.config, like this:
    <machineKey  
    validationKey="21F090935F6E49C2C797F69BBAAD8402ABD2EE0B667A8B44EA7DD4374267A75D7"           
    decryptionKey="ABAA84D7EC4BB56D75D217CECFFB9628809BDB8BF91CFCD64568A145BE59719F"
    validation="SHA1"
    />

    If you're using ASP.NET 2.0, your machineKey tag should also have the decryption attribute, like this:
    <machineKey  
    validationKey="21F090935F6E49C2C797F69BBAAD8402ABD2EE0B667A8B44EA7DD4374267A75D7"           
    decryptionKey="ABAA84D7EC4BB56D75D217CECFFB9628809BDB8BF91CFCD64568A145BE59719F"
    validation="SHA1"
    decryption="AES"
    />

    Note, the above values are just examples! Generate your own values for validationKey and decryptionKey (and keep them secret) using the code from this MSDN page. A modified version is shown below:

    using System;
    using System.Text;
    using System.Diagnostics;
    using System.Security;
    using System.Security.Cryptography;
    
    class App {
    		static void Main(string[] args)
    		{
    			Debug.WriteLine("64-byte validationKey: " + getRandomKey(64));
    			Debug.WriteLine("24-byte decryptionKey: " + getRandomKey(24));
    		}
    
    		public static string getRandomKey(int bytelength)
    		{
    			int len = bytelength * 2;
    			byte[] buff = new byte[len/2];
    			RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
    			rng.GetBytes(buff);
    			StringBuilder sb = new StringBuilder(len);
    			for (int i=0; i<buff.Length; i++)
    				sb.Append(string.Format("{0:X2}", buff[i]));
    			return sb.ToString();
    		}
    }
    

Hopefully the above will help you out if you encounter strange "invalid viewstate" errors, or if you plan to use the viewstate in a web farm, or if you just like knowing more about the viewstate.

P.S. While typing this entry, I accidentally hit the thumb button on my MX510, which by default hits the browser's "Back" button. Which sent me back to the previous page, which made me lose everything I had typed. Which was a super downer. So, disable that mouse button if you don't use it, or you'll be sorry! :)

February 14, 2006    Bookmark to Digg or other social bookmarking
#    Disclaimer  |  Comments [0]