I recently came across this JavaScript code:
function phonescrub(elmt){
str=elmt.value;str2="";ii=0;
while (ii < str.length){
ch=str.charAt(ii);
kk=0;
while (kk < 10){
if (ch==""+kk){str2=str2+ch};
kk++;
}
ii++;
}
elmt.value=str2;
}
It's a little difficult to decipher, so I'll interpret it.
- Start with the current value of the input element (str).
- Initialize the return value (str2) and an indexer (ii).
- Loop through each character in string "str."
- Loop through the numers 0 to 9.
- If the current character (ch) is equal to the number (kk) then append that character to the output string (str2).
- Increment kk [End number loop]
- Increment ii [End character loop]
- Assign the new value (str2) to the input element's value property.
Essentially, what this function does is it strips out all non-numeric characters.
This function has several issues (not the least of which is the variable names "str" and "str2"). But the main issue is the complexity. The method is 11 lines long and it took me 8 steps to explain what it is doing.
Using Regular Expressions, we can reduce 11 lines to 1:
function phonescrub(elmt){
elmt.value = elmt.value.replace(/[^0-9]/g, '');
}
Here is what this new function does:
- Replace all non-numeric characters in the input element's value with an empty string.
- Assign that new string to the value of the input element.
It really doesn't get much simpler than that. And there are no quirky variables (like str and str2).
Today I learned an important lesson about the ValidationSummary control. But first, some background.
The bug I was working on was this: the validation summary did not display the validation errors. The page would repost and redisplay, but there was no messaging as to what might be wrong.
The page was set up in a wizard sort of fashion with about three Panel controls that are displayed selectively, depending on which step the user is on. In order to prevent all the validation controls to fire every time a button is clicked, the various validators were assigned to different validation groups, one for each Panel.
It took me about an hour before I discovered this truth:
"When you specify a value for the ValidationSummary property, only
error messages from the validation controls that are part of the specified group
are summarized. If you do not set a value for this property, all error messages
from validation controls on the page that are not assigned to a validation group
are summarized."
The first time I read it, I was in a hurry and didn't catch the very last part: "...that are not assigned to a validation group..." I guess it is important to read all the documentation.
My bug was that the ValidationSummary did not specify a validation group. According to the docs, that means that only validators that are not assigned a ValidationGroup will show up in the summary control. It was an easy fix (set the validation group when I set which panel to display), but it took me about an hour to figure it out.
I'm currently working on a project where we are storing quite a bit of data in Session for the user. Naturally, QA had a hard time testing whether or not something actually was stored in Session. So, we wrote a little page that showed the values of what we put in Session. The problem with this approach is that every time we added another item to Session, or removed an item, we would have to fix this page to include the new and remove the old. It got to be very tiresome.
I had just finished doing some work with reflection (my first time ever). And it occurred to me that I could use reflection to show everything that was stored in Session in such a way that it could be written once and never need to be updated.
Here's the basic rundown of what the utility does (see attached .zip file):
- On the page load, iterate over all items in Session
- Print the Key of the item
- If the value of the item is a native data type (int, bool, decimal -- including String and DateTime objects) print the value
- If the value is an object...
- Iterate over all the public properties of the object
- Print the Property Name
- If the value of the Property is a native data type, print it
- If it is an object, GOTO #5
In the end, I always get to a native data type (or String or DateTime), so we wouldn't end up in an endless loop. Here's a sample of what it displays:
As an added bonus, it will also display the approximate size of all the objects (in bytes/kilobytes).
This utility has been very helpful for me, to make sure I know what is in Session, without having to step through the code in debug mode and stop and interrogate the Session object to find the specific value (or values) I'm looking for. This has also been very helpful to QA so that they can see what is put into Session.
At my day job, we're in the process of an enterprise re-write. The old stuff is a hodge-podge of Cold Fusion, Java, J# and C#. The website is Cold Fusion so the URLs often look something like this:
http://www.example.com/products/product_details/index.cfm?fuseaction=foo
The new site is ASP.NET. Naturally, the URLs will look somewhat like this:
http://www.example.com/products/details.aspx?item=foo
I'm sure that many of you have been involved in a scenario like this. The business wants to update the site. But we don't want to lose all the SEO ground we've gained over the years. So we have to support the legacy URLs.
There are different ways to tackle this problem: map the ".cfm" extension to be handled by ASP.NET using a custom IHttpHandler; or use an ISAPI filter; or use a third party URL Rewriter. In the end, most (if not all) of these methods rely on Regular Expressions.
Regular Expressions are powerful, but they can be confusing, and many developers avoid them. They're like the ultra-geeky kid in school. You don't really want to associate with him, but you'd love it if he was your lab partner, because you know he'd carry you through anything that you didn't understand.
The task to write the RegExes to match the Legacy URLs with the new URLs has fallen to me. And I'm actually happy about that. The best for me to learn anything is by doing it. So I get to sink my teeth into Regex and hopefully, I won't forget what I learned anytime soon.
And now, the good part - links:
I have recently been learning about the new MVC framework offered by friends at ASP.NET. One of the first questions I had about it was how does AJAX fit into this framework. So, I did a little digging. I found Nikhil Kothari's article on "Ajax with the ASP.NET MVC Framework," but that is not quite what I was looking for.
(Awhile back, I stumbled across Rob Bagby's webcasts on the ASP.NET AJAX client libraries wherein he details the benefits of getting your hands dirty with the JavaScript, instead of letting the UpdatePanel control write all the JavaScript for you. And he goes into detail on how to accomplish that task. He didn't need to do much convincing of me. I've long thought that while the UpdatePanel is very convenient (especially for those who loath JavaScript), it is probably somewhat bloated. In the end, I prefer Rob Bagby's way.)
I was looking for a method that fit within the MVC framework, but didn't deliver HTML from an AJAX call, but rather straight XML, or better yet JSON. I did some more searching and found that Aaron Lerch celebrated the new year with a post titled Unifying Web "Sites" and Web Services with the ASP.NET MVC Framework, wherein he describes how one could go about returning XML or JSON through the MVC framework by simply passing the data to a view and the view determining what form it should send back to the client. I downloaded his provided code only to find that it doesn't work with the latest version of the MVC framework. (Not that this is a big deal. I'm sure I could just study the new framework and re-write it.)
I also found this interesting post by Dan Finch in the forums. It is basically the same concept that Aaron proposed, only less code.
I don't know which is better yet. I'm just learning about this stuff. But I do like how these solutions deliver XML or JSON and they use the MVC framework to deliver it. I'll be keeping an eye out for more like this.
Utilities are among my favorites to code. Especially ones that are short and sweet and useful in many different situations. One of my favorites that I wrote was an Object Serializer.
Most examples of object serialization I have seen end up serializing an object to an XML file. That does have it's purpose. However, I've been in many situations where I'd like to serialize an object into XML and use the XML in code. Or I have XML in the form of a string which I need converted to an object.
The XmlSerializer is what we need. And if you look at the Serialize or Deserialize methods, you see that we have a lot of different options. We need some sort of Writer or Reader in order to do the conversion. Since I want to serialize to and deserialize from a string, the obvious choice was the StringWriter (to serialize) and the StringReader (to deserialize).
It is important to note that both the StringWriter and StringReader classes implement IDisposable and the documentation suggests that we should always dispose of our Reader/Writer when we're done with it. I'm a big fan of the "using" statement which automatically calls the Dispose() method when it leaves the using block.
I also decided to use generics so that I could have a strongly typed object going in and coming out.
So without further ado, here it is:
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml.Serialization;
namespace KevnRoberts.Utilities
{
/// <summary>
/// Used for serializing and deserializing objects
/// </summary>
/// <typeparam
name="T">The type of object to
de/serialize</typeparam>
public class Serializer<T>
{
/// <summary>
/// Converts the XML into an object
/// </summary>
/// <param
name="xml">The XML representation
of an object.</param>
/// <returns>An object of type T.</returns>
public static T Deserialize(string
xml)
{
//
convert to the serializable object
T item;
using
(StringReader reader = new StringReader(xml))
{
XmlSerializer
serializer = new XmlSerializer(typeof(T));
item =
(T)serializer.Deserialize(reader);
}
return
item;
}
/// <summary>
/// Converts an object into XML.
/// </summary>
/// <param
name="obj">The object to convert.</param>
/// <returns>The XML representation of the object.</returns>
public static string
Serialize(T obj)
{
StringBuilder
data = new StringBuilder();
using
(StringWriter writer = new StringWriter(data))
{
XmlSerializer
serializer = new XmlSerializer(typeof(T));
serializer.Serialize(writer,
obj);
}
return
data.ToString();
}
}
}
And here is an example of how you would use it:
string xml = @"<dateTime>2008-04-03T00:00:00</dateTime>";
DateTime deserializedDate = Serializer<DateTime>.Deserialize(xml);
DateTime date = new
DateTime(2008, 4, 3);
string serializedDate = Serializer<DateTime>.Serialize(date);
Of course, you'll want to use it to de/serialize something more complex than a date and time, but you get the point.
Dan Hounshell suggested that in the ASP.NET community, there are three types of people:
- Community Leaders
- Practical Experts
- Developers (i.e. everyone else)
The Community Leaders, he writes, are the people who steer the community. He names Scott Guthrie as the primary steerer. The Practical Experts are people like himself. The ones that write books, present at events, have much read blogs.
Then there are the rest of us. He just calls us "Developers," but I like the term "Developer Barbarians." The Greeks called anyone who wasn't a Greek a Barbarian. Its the "there's Us and everyone who isn't Us" type thing.
Don't get me wrong. I'm not saying that anyone is condescending to us. And I'm certainly not saying that Dan is saying this. These are my words, not Dan's.
In fact, I like the fact that I'm a Developer Barbarian. I know enough to know that I don't know much. That is what makes me a barbarian. I aspire to move up to the "Practical Experts" level, but I'm not there yet.
I wouldn't say that I follow the community and don't study it. I do both. And I do actively seek out better ways to do things. But I'm not always in a position to follow it through to implementation. And most of the time, the "better way" that I found is something that came from the community.
One of the things that I love about software development is that I get to learn new stuff all the time. In fact, if I don't, I'll either search out new stuff to learn (if the job allows it) or I'll look for a new job. And, if time allows, I'll learn stuff on my own at home.
That's what I here to do. Learn. Because it's true. I'm a Developer Barbarian. But I don't want to stay that way.
More Posts