Tag: Web Development

URL parameters with Javascript

So this took me by surprise the other day. JavaScript doesn't have a function to retrieve a URL parameter value. i.e. There is no Request.Querystring command! Of course it wouldn't start Request as it's executing on the browser rather than the server but you would have thought there would be a built in command to do it.

After a bit of searching though I came across this script that does it:

1// Read a page's GET URL variables and return them as an associative array.
2function getUrlVars()
3{
4 var vars = [], hash;
5 var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
6 for(var i = 0; i < hashes.length; i++)
7 {
8 hash = hashes[i].split('=');
9 vars.push(hash[0]);
10 vars[hash[0]] = hash[1];
11 }
12 return vars;
13}

The function returns an array/object containing the parameters and their values. e.g. The following URL:

http://www.example.com/?Name=Tim&Sex=Male

Would return:

1{
2 "Name": "Tim",
3 "Sex": "Male"
4}

To use it in your code you would write

1var name = getUrlVars()["Name"];

And that's it

Converting users from Membership to SimpleMembership

In ASP.NET 2 Microsoft introduced the Membership provider. By many accounts it is not perfect, but as a one size fits all solution it's not bad. Plus it had a major advantage that a lot of other people would also be using it, so if you wanted to grab a forum solution to stick on your site, chances were it would use the same Membership provider.

Now though there is a second Membership provider from Microsoft called SimpleMembership. It simplifies a lot of things that weren't needed with the original Membership provider and also introduces support for working with OAuth providers. Not only that but if you create the MVC 4 project from the default template that is what your solution will be set up to use.

The problem however is Membership and SimpleMembership are not compatible. They store their information in separate tables and if you do try to copy all the users from one to the other, you will soon discover the hashing algorithm used on the password is different. You probably also had all your passwords one way hashed so you can't even generate the new ones.

There is a solution however. Paul Brown has written a nice bit of code to update the MVC 4 account controller so that when your users log in they will first be authorised against SimpleMembership, if that fails it will then authorise against the original Membership and if that succeeds it will generate the new password in SimpleMembership using the one just provided by the user.

Over time as your users log in the will be slowly migrated over. The second time the log in the SimpleMembership will authorise them and the extra code won't even be hit.

http://pretzelsteelersfan.blogspot.co.uk/2012/11/migrating-legacy-apps-to-new.html

Back to basics string vs StringBuilder

This is simple stuff but is something I see people easily miss by just not thinking about it.

A string is an immutable object, which means once created it can not be altered. So if you want to do a replace or append some more text to the end a new object will be created.

A StringBuilder however is a buffer of characters that can be altered without the need for a new object to be created.

In the majority of situations a string is a perfectly reasonable choice and creating an extra 1 or 2 objects when you append a couple of other strings isn't going to make a significant impact on the performance of your program. But what happens when you are using strings in a loop.

A few weeks ago one of my developers had written some code that went through a loop building up some text. It looked a little like this:

1string foo = "";
2
3foreach (string baa in someSortOfList)
4{
5 foo += " Value for " + baa + " is: ";
6
7 var aValue = from x in anotherList
8 where x.name == baa
9 select x;
10
11 foo += aValue.FirstOrDefault().value;
12}

Everything worked apart from the fact it took 30seconds to execute!

He was searching through convinced that the linq expressions in the middle was what was taking the time, and was at the point of deciding it could not go any faster without a new approach.

I pointed out not only had he used strings rather than a StringBuilder, but the loop also created around 10 string objects within it. The loop which repeated a couple thousand times was therefore creating 20000 objects that weren't needed. After we switched froms strings to a StringBuilders the loop executed in milliseconds.

So remember when your trying to work out why your code may be slow, remember the basic stuff.

Image resizing

Using 3rd party components while essential, can also be a headache. All to often you can find yourself spending hours following the setup instructions to the letter only for it to not work. Other times you know it's the exact component you want to use but it seems while the guys may have spent a huge effort in writing to component they seemingly never got round to writing anything to tell you how to use it.

Every so often though I come across a component that works first time and does exactly what you want. One such component that I've found this with recently ImageResizer.

I needed a simple way for images to be resized for a product listing on an eCommerce platform written in Classic ASP. Image resizing can be a real pain, there's the decision of do you do it when the images are uploaded or on the fly, if you do it on the fly there's a a huge number of mistakes you can make and nearly every example of how to do image resizing includes a couple of them. Then lastly in either scenario you need to make sure the end result is actually decent quality.

With image resizer I was done in 5 minutes! It's actually a .NET component rather than Classic ASP but that wasn't an issue. You create a bin folder, add a couple of simple lines to your web.config file then put an extra extension on the image path plus parameters for the size you want and that's it!

If your doing a .NET project it's also available on NuGet making it even easier to get up and running.

Master Page Error

If you're like me you may have gone into design mode in visual studio 2010 hoping to do some work only to be greeted with the following message.

Which initially is a bit confusing, as your site may have just run without any problems. But even so you go to check the placeholders anyway and they look fine. Then you copy and paste the ID's out of the Master Page just to be sure, but still no luck. Check through the Master Page itself and that also looks fine, no squiggly lines to be seen. Finally create a new WebForm linked to the master page, but even this gives the same error.

Now if you have the problem I had, look at the title tag in the Master Page. Does it say <title /> or <title></title>? If it's the first then that's your issue. By default VS2010 will put in the correct tag, but if like me you've just slapped in some HTML from an old project or from a PSD conversion that's been done for you, then chances are you may end up overwriting the title tag as well.

.Net Tip: Default Button for Enter Key

I don't know if I should be happy to now know about this, or just concerned that it's taken me this long to discover. But one issue that surfaces time and time again when programming in ASP.NET, is that issue that pressing enter/return in a text field doesn't always do what you want it to do. 

On a normal website you can have many forms each with their own submit button which becomes the default action when pressing return on one of the forms fields. However in ASP.NET Web Forms there is only ever one form on a page, but there could be 10 different buttons each needing to be the default action for a particular text box. 

The solution as it turns out is very simple and you have two options both introduced in .NET 2.0 (yes that's how old it is!) 

1. Default button for the form. If your page has more than one button, but there is only one that you want to fire when you hit enter then in the code behind you can just type... 

1Form.DefaultButton = Button1

or it can also be specified in your aspx file 

1<form runat="server" defaultbutton="Button1">

2. If you need to be more specific a panel can also have a default button... 

1Panel1.DefaultButton = Button1
2
3<asp:Panel runat="server" DefaultButton="Button1">
Hot Keys Made Simple

Hot Keys Made Simple

Previously I have blogged about how you can create keyboard shortcuts using JavaScript. In other words being able to add functionality to your web app for someone to do a ctrl+s. My previous example wasn't particularly hard and only used 10 lines of code, but this week I stumbled across a jQuery plugin that makes it easier.

http://code.google.com/p/js-hotkeys/

With this plugin, in just 1 line of code you can bind a function to a keyboard shortcut. What's more you don't even need to look up the correct keycodes as it takes a simple text parameters.

1$(document).bind('keydown', 'ctrl+c', fn);

Combine this with a function that just triggers a button click and you have some very cool advanced looking functionality written in around 5 - 10 minuets.

Creating Events in ASP.NET

Creating your own events on your own controls is something that is essential if you want you web app to work well and also provide you with reusable controls. It's easy to skip past the problem and find another way to get your code to do what you want it to do and detect the change another way. But you end up with much nicer code if your controls can have proper events for a piece of action, and you web page can have proper event handlers on each. Not only that but the code you need to write in generally a copy and past job and not that hard.

The Code

While it's not that hard, the amount of code that is needed is quite a lot more than you may expect. Fortunately though it's code you going to just re-use again and again changing small bits as needed.

1//1 - Event args (use default, but eventually pass in data through here)
2public class SaveCompleteEventArgs : EventArgs
3{
4 public SaveCompleteEventArgs(int inDataValue)
5 {
6 this.DataValue = inDataValue;
7 } //end of con
8
9 public readonly int DataValue;
10}
11
12//2 - define delegate
13public delegate void SaveCompleteEventHandler(object sender, SaveCompleteEventArgs e);
14
15//3 - define the event itself
16public event SaveCompleteEventHandler SaveComplete;
17
18//4 - the protected virtual method to notify registered objects of the request
19// virtual so that it can be overridden.
20protected virtual void OnSaveComplete(SaveCompleteEventArgs e)
21{
22 //if the UpdateData event is empty, then a delegate has not been added to it yet.
23 if (SaveComplete != null)
24 {
25 //event exists, call it:
26 SaveComplete(this, e);
27 } //end of if
28}
29
30//5 - method that translates the input into the desired event
31public void TriggeringMethod(int strData)
32{
33
34 // get new event args
35 //EventArgs e = new EventArgs();
36 SaveCompleteEventArgs e = new SaveCompleteEventArgs(strData);
37
38 // call the virtual method
39 OnSaveComplete(e);
40}

Custom Validator Error from Server Side

The built in ASP.NET validators are amazing as we all know. You just drag them on the page, tell them what control to validate, give them a summary control to list the errors and they do it. But what if there's something you need to add server side? Such as something that needs to check with the database before saving. You already have your validation summary control, so it would be nice to re-user that and have everything automatically looking the same. But it would appear there's no easy way of doing it built in, so here's an easy way of doing it... 

Creating a Custom Validation Error

First your going to need a class with some static class's that you can pass your error message to. Here I have two functions one for simply adding the error to the page and the other for adding the error to the page with a specific validation group. I am using a CustomValidator object to make this all work, another option is to implement IValidator but it's actually more effort than's needed. The other section to note is that I'm setting the Error.Text to a non breaking space (this is what would normally go next to the form field you're validating). This is because if you don't then it will default to the ErrorMessage which we only want to go into the summary. If you try setting it to a normal space it will still also default to the summary text.

1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Web;
5using System.Web.UI;
6using System.Web.UI.WebControls;
7
8/// &lt;summary&gt;
9/// Summary description for Validator
10/// &lt;/summary&gt;
11public class ValidationError
12{
13
14 public static void Display(string Message)
15 {
16 Display(Message, "");
17 }
18
19public static void Display(string Message, string ValidationGroup)
20 {
21CustomValidator&nbsp;Error = new CustomValidator();
22 Error.IsValid = false;
23 Error.ErrorMessage = Message;
24 Error.ValidationGroup = ValidationGroup;
25 Error.Text = "&amp;nbsp;";
26
27Page currentPage = HttpContext.Current.Handler as Page;
28 currentPage.Validators.Add(Error);
29 }
30}

Now to trigger the error you just need to called the function as below:

1ValidationError.Display("Useful error message", "ValidationGroupName");

LINQ to SQL Inserts and Deletes

Inserting and Deleting records in a database using LINQ to SQL is just as easy as selecting information. What's not so easy is actually finding out how to do it. There are lots of excellent blog posts around such as this one by Scott Guthrie http://weblogs.asp.net/scottgu/archive/2007/07/11/linq-to-sql-part-4-updating-our-database.aspx, however most of them we're all written for the Beta version of LINQ to SQL which let you do a .Add() or .Remove() on your table, which was  changed on the final release. 

So to insert do something like this: 

1DataClassesDataContext dataContext = new DataClassesDataContext();&nbsp;
2
3//Create my new Movie record
4Movie movie = new Movie();
5movie.Name = "Tim's movie";&nbsp;
6
7//Insert the movie into the data context
8dataContext.Movies.InsertOnSubmit(movie);&nbsp;
9
10//Submit the change to the database
11dataContext.SubmitChanges();

And to delete do something like this:

1DataClassesDataContext dataContext = new DataClassesDataContext();
2
3var movies = from m in dataContext.Movies
4 where m.Name == "Tim's movie"
5 select m;
6
7dataContext.Movies.DeleteAllOnSubmit(movies);
8
9dataContext.SubmitChanges();