Monday, October 1, 2012

Getting rid of "Only secure content is displayed" messages

PROBLEM: You have a secure page(s) on your site (e.g. online payment page) and you are getting "Only secure content is displayed" type warnings in your browser, but you're already using relative URLs for all your assets on your page.

SOLUTION: Have a look at any external assets e.g. Twitter javascript libraries etc. and see how you are linking to them.  You probably have hard coded the protocol - I'd suggest you use protocol-relative hyperlinks (this doesn’t apply to simply linking to another page e.g http://www.twitter.com, only for actual content that is being used on the page e.g. http://twitter.com/javascripts/blogger.js). So instead of having:


            <script type="text/javascript" src="http://twitter.com/javascripts/blogger.js"></script>
            <script type="text/javascript" src="http://twitter.com/statuses/user_timeline/UserXXX.json?callback=twitterCallback2&count=2"></script>

Use this instead:

            <script type="text/javascript" src="//twitter.com/javascripts/blogger.js"></script>
            <script type="text/javascript" src="//twitter.com/statuses/user_timeline/ UserXXX .json?callback=twitterCallback2&count=2"></script>

And this will help you avoid those ugly ‘mixed content’ security warnings which you normally brush under the carpet when browsing the web (obviously make sure that the external sites offer a HTTPS version of their resource).

Some more info is here:

http://weblogs.asp.net/jgalloway/archive/2009/10/15/did-you-know-about-protocol-relative-hyperlinks.aspx

An alternative approach is to use javascript like Google does

   ...
        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
   ....

Friday, September 14, 2012

Multiple HTTP Redirects in IIS 7

PROBLEM: On one of our websites we recently moved from having a separate mobile site vs full site to just having a full site with "responsive design".  We initially just put in place a HTTP Redirect (301) in place via IIS 7 for the mobile site to redirect all mobile pages to the home page of the full site (hoping that people would update their bookmarks after getting redirected) - feedback said people didn't want to update their bookmarks so we needed a way to put in place multiple redirects.

SOLUTION: I couldn't see a way to put multiple HTTP Redirect rules in place easily via IIS 7 for a single site so I decided to use "URL Rewrite 2.0" for IIS 7, a module/extension for IIS provided by Microsoft that has to be downloaded and installed separately (watch out for the first gotcha!)
  1. To install download it from  http://www.iis.net/downloads/microsoft/url-rewrite which will install it via the Web Platform Installer... BUT... be aware, that despite a lack of warning it will:
    1. Stop all the websites on your server.
    2. Require a server reboot before you can use it
  2. After you've scrambled to reboot your server after seeing all your sites down then it's simply a matter of opening the "URL Rewrite" module you'll now see in IIS for your site and creating a number of redirect rules - here is some info: http://www.iis.net/learn/extensions/url-rewrite-module/using-the-url-rewrite-module but this is what I did
    • Requested URL = Matches Pattern
    • Using = Regular Expressions (man, these always suck if you haven't learnt them! A cheat sheet might help you: http://regexlib.com/CheatSheet.aspx ... I find trying to search for regular expressions in regexlib is pointless if it's a general concept you're looking for e.g. "find me all matches with a word but not having this word" vs "email validator")
    • Pattern: e.g. (?!.*timetable.*)^clubs/(.*)/(.*)$
      • Matches any URL that starts with clubs/ and doesn't contain the word timetable
    • Another example: ^clubs/(.*)/(.*)/timetable.*$
      • Matches any URL that starts with clubs/ and then has timetable at the end
    • Ignore case = ticked
    • Action Type: Redirect
    • Redirect URL: e.g. http://yoursite.com/clubs/{R:1}/{R:2}/ (see how you can grab anything from the regular expression that was in brackets (known as a back reference apparently) and use it in the redirect URL.
    • Another example: http://yoursite.com/clubs/{R:1}/{R:2}/timetable/
    • Append Query String = false (not required since we were using friendly urls without query strings anyway).
    • Redirect Type: Permanent (301).
  3. To ensure all other pages are redirected to the root of your homepage simply update your HTTP Redirect settings in IIS
    1. Redirect requests to this destination: Ticked
    2. http://yoursite.com/
    3. Redirect all requests to exact destination (instead of relative to destination).
    4. Status code: Permanent (301).
I'm sure there are better ways out there and would love to hear them.  Otherwise hopefully this helps someone else - at the very least hopefully someone will read the warning about the installation of URL Rewrite causing your sites to stop and the server requiring a reboot!

Wednesday, June 6, 2012

Winforms ListControls (ListBox or ComboBox) binding performance gotcha

PROBLEM: Excessive rebinding can occur with ListControls in Winforms.

SOLUTION: Specifically when the DataSource is changed, or when DisplayMember or ValueMember is changed after DataSource has been set, the binding infrastructure forces the control to rebind. Logically, this makes sense. But it poses a problem if you handle certain control events, in particular SelectedIndexChanged and SelectedValueChanged. In the worst case, the following simple sequence will raise SelectedIndexChanged three times in a row:
listbox.DataSource = dataTable
listbox.ValueMember = "id"
listbox.DisplayMember = "name"

Not a big deal if nothing data intensive is happening in SelectedIndexChanged but in my case it often calls the code to call a webservice. So simply changing the order of these to be as below results in just one SelectedIndexChanged call instead of 3, and hence one webservice call instead of 3.

listbox.DisplayMember = "name"
listbox.ValueMember = "id"
listbox.DataSource = dataTable

This very smart fellow discusses it in full on codeproject: http://www.codeproject.com/KB/database/scomlistcontrolbinding.aspx

Wednesday, April 11, 2012

Checking Server Disk Space

PROBLEM: You have a large network of computers, you want to know when they are getting low on space since that can cause many issues such as websites running slowly or not at all, logs might not get written, defragging can't occur, windows updates can't be applied etc. So you want to monitor them constantly but don't want to waste time doing it.
SOLUTION: I'm sure there are products out there (free and paid for) to do this but my solution was to go the DIY path and use PowerShell and two Windows Scheduled Tasks (one daily that will email any warnings and one weekly that will email regardless). I have zero PowerShell experience but have borrowed liberally from a few fellows (attributions in the script). I'll give you the code and then raise a few points about it:


##############  Script starts Here ##########

# This script is designed to loop through a list of servers in an external file and check the
# space on each drive associated with each server, report on their free disk space percentage
# and output the results to the screen (if run in a console), and an email (which will only get
# sent if the parameter of WarningsOnly is passed when executing the script
# e.g. C:\WINDOWS\system32\windowspowershell\v1.0\powershell.exe -command "C:\ServerDiskSpaceChecker\ServerDiskSpaceChecker.ps1 WarningsOnly").
#
# Acknowledgements:
# DISK SPACE PORTION OF THE SCRIPT TAKEN AND MODIFIED FROM: http://www.youdidwhatwithtsql.com/check-disk-space-with-powershell-2/195
# EMAIL PORTION OF THE SCRIPT TAKEN AND MODIFIED FROM: http://www.techrepublic.com/blog/window-on-windows/send-an-email-with-an-attachment-using-powershell/4969
# EMAIL HTML FORMATTING PORTION OF THE SCRIPT TAKEN AND MODIFIED FROM: http://exchangeserverpro.com/powershell-send-html-email
# SCHEDULING PROCESS (no code required but good to know) TAKEN FROM: http://dmitrysotnikov.wordpress.com/2011/02/03/how-to-schedule-a-powershell-script/



# MODIFY THE BELOW VARIABLES AS REQUIRED

# Issue warning if % free disk space is less
$percentWarning = 15;

# Get server list (text file containing server names)
$servers = Get-Content "C:\ServerDiskSpaceChecker\computers.txt";

# IP address of email server
$smtpServer = "10.10.0.999"

# Email address to send notifications to
$emailTo = "ITTeam@yourcompanyhere.com.au"



# LET'S CHECK SOME DISKS!

$warningsExist = $false;
$scriptParameter = $args[0];
$msgSubject = "Server Disk Space Checker Results";
$datetime = Get-Date -Format "yyyyMMddHHmmss";

# variable for storing body of email (formatted in html so that we can use pretty colours)
$emailBody = "<p>The following are the results of an automated check of remaining server disk space (Refer to the <a href='http://yourwikiurlhere'>wiki</a> for more information). Entries will be marked in red if they fall below the current threshold - please investigate these ASAP.<p>";

# Add headers to log file
Add-Content "$Env:USERPROFILE\server disks $datetime.txt" "server,deviceID,size,freespace,percentFree";

foreach($server in $servers)
{
# Get fixed drive info
$disks = Get-WmiObject -ComputerName $server -Class Win32_LogicalDisk -Filter "DriveType = 3";

foreach($disk in $disks)
{
$deviceID = $disk.DeviceID;
[float]$size = $disk.Size;
[float]$freespace = $disk.FreeSpace;

$percentFree = [Math]::Round(($freespace / $size) * 100, 2);
$sizeGB = [Math]::Round($size / 1073741824, 2);
$freeSpaceGB = [Math]::Round($freespace / 1073741824, 2);

$colour = "Green";
if($percentFree -lt $percentWarning)
{
$colour = "Red";
$warningsExist = $true;
}

# Get results
$results = "$server $deviceID percentage free space = $percentFree% (Total Size=$sizeGB GB, Total Free=$freeSpaceGB GB)"

# Write results to email
$emailBody = $emailBody + "<span style='color:$colour'>$results</span><br />"

# Write results to screen
Write-Host -ForegroundColor $colour $results;
}
}



# Send an email with the details

if(($warningsExist -eq $true) -or ($scriptParameter -ne "WarningsOnly"))
{
Add-PSSnapin Microsoft.Exchange.Management.Powershell.Admin -erroraction silentlyContinue;

$msg = new-object Net.Mail.MailMessage;
$smtp = new-object Net.Mail.SmtpClient($smtpServer);
$msg.From = "system@yourcompanynamehere.com.au";
$msg.To.Add($emailTo);
if($warningsExist -eq $true)
{
$msgSubject = "Warnings Exist - " + $msgSubject;
}
$msg.Subject = $msgSubject;
$msg.IsBodyHTML = $true;
$msg.Body = $emailBody;
$smtp.Send($msg);
}


############## End of Script ##########

To enable the PowerShell script to run permissions needed to be changed on the server to allow local scripts to run ok (but external scripts require signing) - run this command in PowerShell:

  • Set-ExecutionPolicy RemoteSigned
There are a number of variables within the script that can be modified:
  • $percentWarning (Issue warning if % free disk space is less)
  • $servers (text file containing server names))
  • $smtpServer (IP address of email server)
  • $emailTo (Email address to send notifications to)
To specify which servers to check, create a file (e.g. computers.txt) and simply have a list of server names, one on each row, no empty rows at the end, and ensure the $servers variable uses that file.

When executing the script, if you want it to only email you when there is a warning then pass the parameter "WarningsOnly" after the script name (provide any other value if you want to always be notified) e.g. C:\WINDOWS\system32\windowspowershell\v1.0\powershell.exe -command "C:\Server Disk Space Checker\ServerDiskSpaceChecker.ps1 WarningsOnly"

To troubleshoot run the script/scheduled task manually - if you include the -NoExit flag when running the script it will not close the PowerShell window when it's done so you can see any errors etc that may have occurred.
    Common problems include:
    • Incorrect server name in computers.txt
    • Blank lines in computers.txt
    • Incorrect script permissions (refer above)
    • NaN% in the email (this means the script has had a problem reading the disk space - NaN stands for Not a Number - add the -NoExit flag and see what's happening).
    This script is basically a Frankenstein compliation of a few different scripts (refer to the URL references within the script itself) - I'm definitely no PowerShell expert, but it seems to do a good job when combined with the schedule task and parameters. (apologies for the blog formatting - I'm really not a big fan of the Blogger formatting!).

    Thursday, February 23, 2012

    CustomValidator not firing with TextBox

    PROBLEM: You've added a CustomValidator control to your page and for some reason the validation isn't firing.
    SOLUTION: In my case it was ValidateEmptyText="true" needed to be added. Also if you're using multiple validation groups on the page make sure you set your ValidationGroup property as well.

    Also remember when you use a CustomValidator to ensure you add a Page.IsValid check on your submission button to prevent anything progressing further if the custom validation is false.

    Friday, January 20, 2012

    Windows Services

    PROBLEM: Recently I created a simple windows service with .net 4 to perform a check periodically on the status of our company's websites (are they up or not) and send an email notification if they aren't.

    SOLUTION: While not particularly challenging there definitely some lessons learnt...
    • Firstly, people (http://weblogs.asp.net/jgalloway/archive/2005/10/24/428303.aspx) will point out that probably creating a console program which can be scheduled with the windows scheduler is the easier and better approach to this problem, but I mainly just wanted the experience in creating a windows service.
    • Some good web service examples:
    • Add a try/catch around your code in Main which logs any exceptions - useful to determine problems if your service won't start correctly etc.
    • To debug a windows service in Visual Studio you need to open the solution and then choose Debug > Attach to Process... > Tick both "Show processes from all users" and "Show processes in all sessions" and then click the exe and choose Attach. Set a breakpoint and away you go (remember to stop the timer while debugging if it is set to raise an event frequently otherwise you won't be able to step through the code easily).
    • When using windows logging, logs are identified by their first 8 characters - if you try and create two different logs, with the same first 8 characters, it will cause an exception.
    • The HttpWebRequest.GetResponse method returns various HttpStatusCode enums BUT quite often will raise an exception (e.g. if the website is down), so make sure you use a try/catch and it is from the exception (cast to WebException) that you can get the HttpStatusCode i.e. WebException.Response.StatusCode).
    • When you create a new log (not a new entry within a log), the windows Event Viewer doesn't do a great job at refreshing and showing it (even when you choose refresh) - just close the Event Viewer and open it again.
    • If you are testing a service and constantly installing and uninstalling it, you may get the system into a state where the install starts failing or complaining that the service has been marked for deletion but can't be removed. Try shutting down the Services window and see if that makes a difference, or try manually uninstalling it view Add/Remove Programs or via installutil /u but usually you'll just resolve it quicker by restarting your computer.
    • If you want to use an app.config with your windows service, you'll need to manually add a reference to the System.Configuration DLL so that you can use ConfigurationManager.AppSettings["BLAH"] (it's not included by default in a windows service project).