Friday 27 November 2009

ASP.NET: Validate email address input using a Regular Expression

A nice way to validate an email address which has been entered, using a Regular Expression and absolutely no additional code:

Add a texbox for the input:
<asp:TextBox ID="TextBoxEmail" runat="server" Text='<%# Bind("Email") %>' Width="200px" MaxLength="255"></asp:TextBox>

Then, add a RegularExpressionValidator:
<asp:RegularExpressionValidator ID="regexpName" runat="server"
ErrorMessage="Enter a valid email address" ControlToValidate="TextBoxEmail" ValidationExpression="^([0-9a-zA-Z]([-\.\w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$" />


Job done - no code, no fuss. It's pretty robust, too.

Thursday 26 November 2009

ASP.NET: Setting the maximum number of characters in a multiline text box

Bizarrely, ASP.NET includes an out of the box setting which allows you to set the maximum number of characters on an ordinary text box, but not on a multiline text box.

Now there may be a good reason for this, and if there is I would love to be enlightened.

There is no less need for a multiline textbox control to be properly validated than any other text box - perhaps it is even more important since the user might have spent ages typing something in, only to be rebuked for exceeding the maximum number of characters and to be punished by losing what they'd typed.

A friendly character on the ASP.NET forums offered this simple JavaScript solution:

<script language="javascript">

function Count(text,long)
{

   var maxlength = new Number(long); // Change number to your max length.

   if (text.value.length > maxlength){

      text.value = text.value.substring(0,maxlength);

      alert(" Only " + long + " chars");

   }

}
</script>


Then just add these to the multiline textbox's markup: onKeyUp="Count(this,200)" onChange="Count(this,200)".

Wednesday 25 November 2009

ASP.NET: Adding Error Handling With Email Notifications

If you're developing a new application, the temptation is often to get it completed and deployed in the shortest time possible. And sometimes that may come at the expense of proper error handling. So with the best will in the world, sometimes problems do occur in a Production database and the users see an error.

And with no error handling in your application, that can be a pretty poor experience for the user which can make you look a bit unprofessional and can potentially expose your application to security issues if your settings allow the user to see the Exception Details Yellow Screen of Death. So after I completed a deployment of a major release, I decided it was time to implement some error handling and to enable my application to automatically email me with details of any errors which occurred in Production.

One of the things think is brilliant about .NET is the documentation. It's terrific. There are tutorials on every subject, and error handling within ASP.NET is very well covered. So basically, the steps to implement are as follows:

1. Add a custom error page with the appropriate look and feel
Rather than me plagiarise the tutorials on the official ASP.NET web site, here's a link to a tutorial which explains the concepts involved and will get you up and running with a custom error page which, depending on the type of error, shows a nice message to your users, rather than the Yellow Screen of Death (YSOD):



2. Add a Global.asax file to enable application-wide error handling
If you followed the tutorial above, when an error occurs the user sees a nicely formatted error message which is in keeping with the rest of your application. But nothing is really done about the error. It's equally important that you are notified of the error, and that you can investigate it with a view to resolving it.

So the next step is to enable your ASP.NET application to catch any errors, application wide. This is done by adding a Global.asax file which has event handlers for various different application wide events, including trapping errors. The next tutorial from the ASP.NET website explains the concepts involved and helps you to get an error handler set up. It also shows you how to automatically notify you via email when an error occurs.

Remember, when pasting any code from the example into your project that you need to import System.Net.Mail at the top of your Global.asax page in order to identify the appropriate classes for sending mail. You also need to add the appropriate mail server settings to your web.config file (you might need to specify a port number and username and password):

<system.net>
<mailSettings>
<smtp>
<network host="mailhost.*****.net" />
</smtp>
</mailSettings>
</system.net>

So now if you've done things by the book, you should be set up to be automatically notified of the details of any errors which occur, and the users should see a nice friendly screen rather than the horrible YSOD.

Finally, I'm a big fan of using XML for configuration settings where possible, rather than hard-coding them into the application. So you can add some keys to your web.config file which contain the settings you want to use for your email notifications. You could add something like this to appSettings inside your web.config:

<!-- Settings used for email error notifications -->
<add key="ErrorToAddress" value="support@example.com"/>
<add key="ErrorFromAddress" value="aspApp@ example.com"/>
<add key="ErrorEmailSubject" value=" aspApp: An error has been logged"/>

Then, in your Global.asax file, replace the hard coded values with a call to extract these settings from your web.config:

' Get the appropriate values from the web.config file
Dim ToAddress As String = ConfigurationManager.AppSettings("ErrorToAddress")
Dim FromAddress As String = ConfigurationManager.AppSettings("ErrorFromAddress")
Dim Subject As String = ConfigurationManager.AppSettings("ErrorEmailSubject")

This all worked for me, and now my application is more robust, the users don't see any horrible error messages and if any problems occur in Production I'll know about it pretty quickly.

Hopefully, this might help you to consolidate the necessary parts of what's required to implement some error handling within your application too. But of course, this is no replacement for using proper try-catch error handling where appropriate.

Friday 20 November 2009

After Upgrading to .NET Framework 3.5: ASP.NET Reconfiguration and Reporting Services 403 error

Due to the issues I had with the .NET Framework and SQL Server Integration Services, I had to roll back the version to 3.5 instead of 3.5 SP1.

When the upgrade from 3.0 to 3.5 was completed, I had to do a few things to get IIS working again (I was getting errors when attempting to browse to my ASP.NET web sites, and a 403 forbidden error when browsing to a Reporting Services page):

- Re-register ASP.NET (aspnet_regiis -i from the .NET Framework directory).
- Enable ASP.NET in the Web Service Extensions section of IIS Manager.
- Check that each application was set to use the correct version of ASP.NET
- Check that each application was still set to the correct Directory Security settings.

At this point, the ASP.NET web sites started working again but Reporting Services was still giving me a 403 forbidden error.

To get this resolved, I had to delete the ReportServer Virtual Directory in IIS, and then recreate it using the Reporting Services Configuration manager.

All working again!

I Lost My iPhone!

Devastated.

I was at the Kasabian concert at the SECC last week (which was absolutely amazing). At the last song which of course was LSF, I got a text saying that the wife was waiting outside for me to give me a lift.

I took the phone out to text her back since otherwise she would have no idea how long she would be waiting, and someone knocked my arm hard. My much prized iPhone was launched into the blackness of the undulating crowd in front at what seemed like warp speed.

Immediately I went after it and created a space in the crowd with my flapping arms and panicked expressions. A few people around me noticed that I was looking for my phone and joined in the search, but it was never looking good.

The concert finished and after a few more minutes of scanning the floor for a stricken and stamped on iPhone, we were ushered out of the arena by the SECC staff. I reported it to the Control Room at the SECC, the police and O2.

Over the few days that followed, I realised how much I have grown to depend on my iPhone. Not only for the phone calls and text messages, but for the instant access to my email, Facebook and being able to find out the answer to just about any question I could think of just by firing up Safari. It's hugely sad, I know.

Thankfully, the phone is insured via my Lloyds TSB bank account. They have a deal with Lifestyle Services Group, and I've been using them to insure my phones for years. In the past when I had to make a claim, I'd just phone them up, tell them what happened, pay the excess and a new phone would be with me a couple of days later.

Not this time. What a palava.

Everything is now done via mail and fax, which seems like a step back to me. I had to prove that I had reported it to the Police, O2 and them within 48 hours (thankfully I had) and provide proof of purchase. So the claim form is now with them and I'm hoping that I will be receiving a nice new, shiny iPhone sometime soon. If not, I'm gonna be in trouble.

The lesson for me? Don't take it to concerts, sign up to MobileMe (if I had done this, I might've been able to find the phone via the GPS tracker if it wasn't broken) and keep backing everything up.

Though I do have to admit, I have quite enjoyed using the ancient backup phone which has the ability to make and receive calls, and to send and receive texts - and that's it. It's a simpler way to be, no personal data to worry about, no time spent on checking Facebook or emails, and no notion of entertainment on the go.

That said, give me an iPhone any day. Please, Lifestyle Services Group, give me an iPhone.

Existing SSIS Packages Generating New Errors (.NET Framework)

I had been using an SSIS package to load in data from a remote database using the Sybase Adaptive Server Enterprise driver on my own machine and on two 64 bit servers.

The load was working fine, but then it stopped working suddenly complaining of error code 0x80131937:

* Error 0xc0209029: Data Flow Task: The "component "Source - Query" (1)" failed because error code 0x80131937 occurred, and the error row disposition on "output column "WhseCode" (12)" specifies failure on error. An error occurred on the specified object of the specified component.
(SQL Server Import and Export Wizard)


But the weird thing was that the exact same DTSX package stopped working on my PC and on only one of the two servers - it kept working on one of them.

So I tried everything:

- Stopping the package from failing on error to see what rows would be loaded into the database - every row loaded but every column was set to NULL.
- Rolled Sybase driver back to ASE ODBC 12.5 - this actually worked, but I could not roll the drivers back on the server machines so I had to find another answer.
- I tried several different query formats, but it failed every time.

Then, I stumbled across this thread and the good advice on the .NET framework versions proved to be the answer.

On my local workstation machine and the server which stopped working, I had .NET 3.5 SP1 installed. But on the server which was still working, the .NET framework was 3.5 without SP1.

Basically, I removed all versions of the .NET Framework, reapplied .NET 2.0, 2.0 SP1, 3.0 and 3.5 in order and tested the package between each installation.

Now it's working and the data is loading in just as it should.

I can't believe that .NET 3.5 SP1 would just break ADO like this. I don't have a problem with compatibility issues between versions of .NET, but some explanation or notification would be useful.

Oh well, the things you learn.

Tuesday 17 November 2009

The Horrors of Internet Explorer 6: Detecting a Visitor's Web Browser

I tend to keep up with updates to browsers, so I left Internet Explorer 6 behind in a cloud of dust a long time ago. It's horrible, and craps all over CSS in a way which beggars belief.

So much so, that several online campaigns have been set up to try to get rid of Internet Explorer 6. After all, it is eight year old technology - and a LOT has changed since its release in August 2001.

So when I discovered that my own website looks absolutely horrible through IE6, I realised that I had to accommodate this somehow.

The market share of IE6 has been dropping steadily throughout 2009, and at the time of writing, accounts for roughly ten percent of browsers on the web.

Rather than try to accomodate such a terrible piece of browser technology, I have decided just to display a message to IE6 users telling them that the site doesn't work for their browser and that maybe it's time for an upgrade.

Now I realise that a lot of people would object to this, shouting claims of lost custom due to IE6 users just closing the site, and that not everyone can upgrade from IE6 (standardised corporate PC builds etc).

But I am willing to sacrifice that potential ten percent of visitors to save myself from a complete site redesign which would be out of date in a year when the last IE6 users finally upgrade to something a bit more robust. I also think that some of those ten percent would have another browser on their system, which they may just use to access sites which don't show up properly in IE6 (there must be a few).

Anyway, the point is that there is a really simple way to detect which version of IE is being used, and display custom messages to the user or to show/hide certain parts of a web page. This excellent blog post highlights how it can be done in detail, but basically detecting IE6 can be done using the following simple conditional comment (which is only parsed by Internet Explorer browsers):

<!--[if IE 6]>
Special instructions for IE 6 here
<![endif]-->

Now, a custom message can be displayed and problematic sections of the site can be hidden for IE6 users.


Simples!

Monday 9 November 2009

Firefox: This address uses a network port which is normally used for purposes other than Web browsing.

When browsing to some sites using Firefox, I got the message:

"This address uses a network port which is normally used for purposes other than Web browsing. Firefox has cancelled the request for your protection"

When you see this message, Firefox completely blocks you from accessing the site you have requested. Since people often need to access non-standard ports for development purposes, this is stupid - the kind of 'nanny' behaviour you would expect from Microsoft, not a company who are normally very 'developer friendly'.

There is of course, a way around it:

1. Open Firefox
2. Type about:config in the address field
3. Right click anywhere on the screen
4. Click new > string
5. Enter preference name as: network.security.ports.banned.override
6. Enter string value as: 2049 (or whatever port number you want)

When you attempt to visit the site again, Firefox will allow it since you have added an exception for the selected port.