Creating a Page method (ScriptMethod) within an ASCX user control using AJAX, JSON, base classes and reflection

I have searched far and wide for the past week looking for a way to create a page method (a neat feature in ASP.NET which allows you to call static methods in your page decorated with an attribute as an AJAX web service) in an ASCX user control and possibly even a master page. First, a little background… (yes, there will be a code download link at the end of the article)

I am currently working on an enterprise level ASP.NET AJAX application to be used in a call center, as most of the applications I create are for use in call center automation and task management. Because Update Panels are evil and this application was riddled with them, I have been slowly but surely stripping them out one by one. The problem, the application loads 90% of its screens and functionality based on configuration data, dynamically building pages and loading user controls located in both ASCX files and server controls located in external assemblies bound at run-time. The major roadblock is that our middle tier is all WCF, which works great, however they are all on a different domain than the web application and use secure SOAP (not REST), therefore I can’t call them from JavaScript. Not only that, there are only 4 pages in the entire application, everything else is dynamic. With over 130+ and growing user controls, and plug-and-play custom functionality, it would be impossible to put all of these methods in copy-cat services using WCF in the web application itself. Did I mention that the site uses a dozen or so host headers in IIS, which rules out WCF hosted svc files in the web site right there. Page methods seemed like a perfect fit, only I wasn’t about to put 200+ web methods on a single page when only one or two user controls would ever use them. That would be stupid and the JavaScript would take forever to compile in even a fast browser.

Everything I found on the web searching Google, MSDN forums, user groups, etc has turned up one and only one answer to my dilemma: “This can not be done, only public, static methods on an actual ASPX page may contain page methods in this manner because ASCX controls do not have their own unique post-back address like a page does.” I thought to myself, “This is stupid!” Of all the brilliant things Microsoft has done with ASP.NET you would think that they would have built the ability to register methods dynamically on the page through a child control, whether a user control or master page, either as a callback, delegate, etc, at least some model for doing this, but alas, apparently myself and the hundreds of other posters out there have not been diligent in filling out feature requests for this item, which I will do sometime later this week.

The solution:

While ASCX user controls may not contain page methods (ScriptMethod), pages can. Duh, right! So why can’t I create a single, general page method in my base page class which all of my site pages inherit from, and provide a means, through reflection and custom attributes, along with my base user control class that all my ASCX user controls ultimately inherit from, to dynamically create JavaScript wrappers for calling my page’s single page method, which in turn knows how to invoke my user control type’s public static method, passing in any collection of parameters and even providing a wrapper for JSON serialization of the method’s result back to the client, INCLUDING ANONYMOUS TYPES!!! OK, now I’m on to something.

The end result is a custom attribute which my base user control class detects on static, invoking, public methods, which then registers some well-crafted JavaScript script block with the page’s ScriptManager, which in turn know how to invoke the page’s ScriptMethod dynamically passing in some information about the type name and method name to invoke through reflection.

Now, to the code

First, we need to create an attribute to attach to our ultra-nifty public static methods in our user controls that we want to expose to our client as ScriptMethods. I’m going to call my attribute UserControlScriptMethodAttribute, but you can call it whatever you want. This is a very simple attribute, not much to do here. You could add some validation that it’s on a static and public member, but that’s up to you.

[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
public sealed class UserControlScriptMethodAttribute : Attribute
{
    /// <summary>
    /// Initializes a new instance of the <see cref="UserControlScriptMethodAttribute"/> class.
    /// </summary>
    public UserControlScriptMethodAttribute() { }
}

BasePage.cs

Then, I needed my base implementation for the “generalized” ScriptMethod. This would be on the page class that all of my pages inherit from, exposing the capability of using these ScriptMethod from any user control or master page that I want to.

There are several important things going on in the base page class. First, I needed to create my script method. This method has a simple signature, basically taking a fully qualified type name (including the assembly if need be), as well as the method name to invoke in that type and a boxed object array for any additional arguments which should be passed through as parameters when invoking the method. I’ve hard-coded my response format as JSON and HttpGet=false. You could theoretically create several versions of these method for different options and add these options as well to your custom parameter for consumption, but I didn’t need anything that sophisticated here.

[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json, UseHttpGet = false)]
public static string PageServiceRequest(string typeName, string methodName, object[] args)
{
    Type ctl = Type.GetType(typeName);
    if (ctl != null)
    {
        object o = ctl.InvokeMember(
            methodName,
              System.Reflection.BindingFlags.Static
            | System.Reflection.BindingFlags.InvokeMethod
            | System.Reflection.BindingFlags.Public
            | System.Reflection.BindingFlags.IgnoreCase,
            null, null, args ?? new object[]{});
        if (o != null)
        {
            if (o is string || o.GetType().IsValueType)
                return o.ToString(); // If it is a string or value type, return a string

            // If it is a complex object, return a serialized version of it.
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            return serializer.Serialize(o); // allow anonymous types, etc
        }
    }
    return "{}"; // return an empty JSON object
}

Notice that once I get the Type I need from the type name, getting the method using some simple binding flags is rather easy, then invoking it passing the arguments object array straight through. From there, I take the result of the method invocation and determine if it is a value type or a string, if it is, I simply return the value.ToString(), otherwise I’m serializing it to JSON and still returning a string (only this string is JSON). The JavaScriptSerializer even allows me to take an anonymous type from the invocation target and serialize it directly back to the client in JSON without having to any further work, which you’ll see a little later in this article, is really freakin’ cool!

Next, I need to expose a more friendly wrapper around the ScriptMethod in JavaScript so my user controls will have to know less about how to invoke this guy and it makes it a bit more usable.

private void RegisterPageServiceRequestProxy()
{
    ScriptManager.RegisterClientScriptBlock(
        this,
        GetType(),
        "PageServiceRequestProxy",
        "function InvokeServiceRequest(typeName,methodName,successCallback,failureCallback){if(PageMethods.PageServiceRequest){try{var parms=[];for(var i=4;i<arguments.length;i++){parms.push(arguments[i]);}PageMethods.PageServiceRequest(typeName,methodName,parms,successCallback,failureCallback);}catch(e){alert(e.toString());}}}",
        true);
}

Wow, this a really long, condensed line of JavaScript which you don’t necessarily need to understand, other than the fact that it really will make life easy for you. Essentially it creates a wrapper method taking the type name, method name, callbacks and allows you to pass in any number of additional arguments… as many as you want after the failure callback. This wrapper will then simply take those extra parameters and build an Array object to pass as the “args” parameter to the base ScriptMethod. I need to call this method OnInit as seen below:

protected override void OnInit(EventArgs e)
{
    base.OnInit(e);
    RegisterPageServiceRequestProxy();
}

BaseUserControl.cs

Our base user control, which all ASCX pages will inherit is a bit more involved. For one, we need to obfuscate the innards of how our new attribute is consumed. We also want to hide all the minutia around passing fully qualified type names and method names, etc. We also want to expose some nicely formed methods on the client via JavaScript that can be called using the same method name and similar parameter signature as the method in the ASCX code-behind, with the exception of the callback client methods (the whole point of asynchronous client processing).

First, I want to emit and register my scripts and “stuff” during the Pre-Render phase of the page life-cycle, so I’m going to override OnPreRender to call my register method.

protected override void OnPreRender(EventArgs e)
{
    base.OnPreRender(e);
    RegisterUserControlWebMethods();
}

Next, let’s build out the implementation of our RegisterUserControlWebMethods method stub. I made it private because it doesn’t need visibility outside of our base class, remember our attribute will take care of this for us.

private void RegisterUserControlWebMethods()
{
    foreach (MethodInfo method in this.GetType().GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod))
        if (method.GetCustomAttributes(typeof(UserControlScriptMethodAttribute), true).Length > 0)
            RegisterUserControlWebMethod(method);

    Type baseType = this.GetType().BaseType;
    if (baseType != null && (baseType.Namespace == null || !baseType.Namespace.StartsWith("System")))
        foreach (MethodInfo method in baseType.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod))
            if (method.GetCustomAttributes(typeof(UserControlScriptMethodAttribute), true).Length > 0)
                RegisterUserControlWebMethod(method);
}

In the example above, you can see our initial search within the current type for any methods with the appropriate binding flags, being static, public and invoke, as well as a test for our custom attribute. If we find any, for each one that we find we’re going to further call our RegisterUserControlWebMethod (more on this in a few lines). You’ll notice that we also do a second round through reflection to get the base type and check any methods in there for these super special attribute decorated methods. I could have made this a bit cleaner in the recursion department, but again, I didn’t need to for my purposes, I’m sure there are better ways to do this. The reason I’m doing this second loop on base types is simple, depending on your project structure, either a Web Project or Web Site, you will find that your methods exist not in the current type, but the base type as the current type you have loaded is some temporary type drummed up in the CLR at run-time or located in a special page or directory assembly, etc.

Now that we’ve found the methods we need to be able to invoke on the client, we need to emit and register wrappers for those methods, obfuscating the details around type names, method names, etc and providing a neat and concise means of invoking them on the client.

private void RegisterUserControlWebMethod(MethodInfo method)
{
    string blockName = string.Concat(method.Name, "_webMethod_uc");

    StringBuilder funcBuilder = new StringBuilder();
    funcBuilder.Append("function ");
    funcBuilder.Append(method.Name);
    funcBuilder.Append("(successCallback,failureCallback");
    foreach (var par in method.GetParameters())
        funcBuilder.AppendFormat(",{0}", par.Name);
    funcBuilder.Append("){if(PageMethods.PageServiceRequest){try{var parms=[];for(var i=2;i<arguments.length;i++){parms.push(arguments[i]);}PageMethods.PageServiceRequest(");
    funcBuilder.AppendFormat("'{0}','{1}'", method.DeclaringType.AssemblyQualifiedName, method.Name);
    funcBuilder.Append(",parms,successCallback,failureCallback);}catch(e){alert(e.toString());}}}");

    ScriptManager.RegisterClientScriptBlock(this, GetType(), blockName, funcBuilder.ToString(), true);
}

The RegisterUserControlWebMethod method takes the method info through reflection and builds a JavaScript function with the same name as the method, then adds the appropriate callback parameters which are always the first and second parameter respectfully, then takes the parameter collection (much like the base page registered method did) and passes those an a JavaScript Array, invoking the PageServiceRequest through the PageMethods namespace. When invoking the PageServiceRequest method, it also passes the fully qualified type name of the method info’s declaring type and the method name through reflection, keeping these values in the function wrapper as coded string values.

ServerTime.ascx

ServerTime is my example User Control which gets loaded on a simple page, Default.aspx. There i no code on Default.aspx, therefore there is no need to put anything here for it. All I did was drop the ServerTime.ascx user control onto the designer surface of Default.aspx in Visual Studio so the page would host my user control. Keep in mind I’m setting my base page type and base user control type in my web.confg as shown here:

<system.web>
    <pages pageBaseType="ScharfHoldings.BasePage" userControlBaseType="ScharfHoldings.BaseUserControl"

The code-behind file, ServerTime.ascx.cs looks like this below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class ServerTime : ScharfHoldings.BaseUserControl
{
    [ScharfHoldings.UserControlScriptMethod]
    public static string GetTime()
    {
        // Return a simple string to the client. This by-passes serialization since it is only a string.
        return DateTime.Now.ToLongTimeString();
    }

    [ScharfHoldings.UserControlScriptMethod]
    public static ComplexTime GetComplexTime()
    {
        // Return a strongly typed object instance to the client.
        return new ComplexTime() { Time = DateTime.Now.ToLongTimeString(), MachineName = HttpContext.Current.Server.MachineName };
    }

    [ScharfHoldings.UserControlScriptMethod]
    public static object GetAnonymousTime()
    {
        // Return an anonymous type instance to the client.
        //    this anonymous type is intended to mimic our ComplexTime type, only it is anonymous, however will
        //    behave the exact same when it is serialized to the client through JavaScript.
        return new { Time = DateTime.Now.ToLongTimeString(), MachineName = HttpContext.Current.Server.MachineName };
    }

    [ScharfHoldings.UserControlScriptMethod]
    public static object GetTimeWithParameter(string clientMessage)
    {
        // Return an anonymous type instance to the client.
        //    The clientMessage parameter gets passed in dynamically from the client and we're going to set the
        //    MachineName property to this value to pass back from the server to prove we got the client value in the parameter.
        return new { Time = DateTime.Now.ToLongTimeString(), MachineName = clientMessage };
    }

    [Serializable]
    public class ComplexTime
    {
        public string Time { get; set; }
        public string MachineName { get; set; }
    }
}

As you can see I have 4 of my custom script methods to show-case the different capabilities built into this methodology. One is a simple call, with no parameters, which returns a string.

GetComplexTime takes no parameters and returns an object of type ComplexType which has a property, Time and MachineName.

GetAnonymousType showcases the ability for this method to return anonymous types to the client, which is a very powerful feature and presents itself more like JavaScript rather than .NET. The anonymous type I am created here is intended to look exactly like ComplexType for no other reason than to re-use code on client and show it can be done.

GetTimeWithParameter takes a simple type parameter (a string in this case) and returns another anonymous type, but this time plugging the parameter into the MachineName property instead of the server’s machine name. This again is for ease of example and code re-use.

Now, let’s take a look at the client side of this. First, I have a simple structure for displaying my data and a button to invoke all of my server methods asynchronously:

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="ServerTime.ascx.cs" Inherits="ServerTime" %>
<div id="myTime">
    <div id="time"></div>
    <div id="complexTime"></div>
    <div id="anonymousTime"></div>
    <div id="parameterTime"></div>
    <input type="button" id="refreshMe" value="Get Time" title="Click here to refresh the time from the server" onclick="refreshTime();return false;" />
</div>

As you can see, I have a DIV for each method result to show the results of each method call and a simple button labeled Get Time that will call a simple JavaScript function, that in turn calls all of my user control Script methods.

Here is what the page and user control look like upon their initial state:

InitialState

Now we need to make the button do something interesting. Below is the JavaScript block that provides the method that executes all the other methods, refreshTime() as well as the callback methods for success and failure of each ScriptMethod call that we make. the last two methods are simply for displaying the results of the script methods in their respectful DIV elements.

<script type="text/javascript">
//<![CDATA[
    function refreshTime() {
        try {
            // Call the UserControlWebMethod attributed functions on the server.
            GetTime(refreshTime_Success, refreshTime_Failure);
            GetComplexTime(refreshTimeComplex_Success, refreshTimeComplex_Failure);
            GetAnonymousTime(refreshTimeAnonymous_Success, refreshTimeAnonymous_Failure);
            GetTimeWithParameter(refreshTimeWithParameter_Success, refreshTimeWithParameter_Failure, 'the Client... Hi!');
        }
        catch (e) { alert(e.message); }
    }

    // Delegate functions for the GetTime method
    function refreshTime_Success(result) { displayTime(result); }
    function refreshTime_Failure(result) { }

    // Delegate functions for the GetComplexTime method
    function refreshTimeComplex_Success(result) { displayComplexTime(result, $get('complexTime')); }
    function refreshTimeComplex_Failure(result) { }

    // Delegate functions for the GetAnonymousTime method
    function refreshTimeAnonymous_Success(result) { displayComplexTime(result, $get('anonymousTime')); }
    function refreshTimeAnonymous_Failure(result) { }

    // Delegate functions for the GetTimeWithParameter method
    function refreshTimeWithParameter_Success(result) { displayComplexTime(result, $get('parameterTime')); }
    function refreshTimeWithParameter_Failure(result) { }

    // Simply set the innerText of the simple time element from the raw result of the service method.
    function displayTime(timeAsString) {
        document.getElementById('time').innerText = timeAsString;
    }

    // Evaluate and parse out the JSON object to a type using eval, then build a display string and display the result.
    function displayComplexTime(timeAsObj, ctrl) {
        try {
            var obj = eval('(' + timeAsObj + ')');
            if (obj) ctrl.innerText = obj.Time + ' on ' + obj.MachineName;
        }
        catch (e) { alert(e.message); }
    }
//]]>
</script>

As you can see, when we’re getting back an object (rather than a simple or value type) we have to call eval() on that object’s JSON string, wrapped in parenthesis in order to get the actual object instance from the JSON (otherwise it is still just a string). Once I have an instance from the JSON using eval, I can get property values from that object, such as you see here, which are exactly the same name as the properties specified in both the ComplexTime class, as well as both uses of the anonymous types.

The end result looks like this once I click the button (notice, depending on your computer’s speed, you may see all the lines appear or refresh at the same time or like me you may see a slight delay in the asynchronous processing of each of the methods.

ButtonClicked

Viola! That’s all there is to it. NEVER let anyone tell you ever again that you can’t create page methods in an ASCX user control, because using these technique, you most definitely can!

Source Code Download

I’ve created a simple, sample web site in Visual Studio 2008, .NET 3.5 to show off the capabilities and give you a starting point to play around with the code. This is the full working source code that I based the article on. I look forward to getting your comments, feedback and improvements you’ve made or found or any bugs you might have encountered. I’m really excited about using this functionality and have already been successfully incorporating it in our enterprise software with great success. Enjoy!

~ Chad.

Silverlight 3 for the Enterprise – Part 1

I will be covering architectural patterns and design for an enterprise level Silverlight 3 application. Silverlight here is really a misnomer since the UI does not truly identify an enterprise level application, but rather the tiers and application components that make up an extensible, flexible and scalable group of systems. More »

3-State CheckBox using Microsoft AJAX

Preview

Blank (or unset): blank, Checked (or granted): checked, and unchecked (or denied): unchecked.

I recently had some very difficult requirements to fulfill on an access control and configuration application with a web front end. Those of you who have designed or implemented access control interfaces know this is a daunting task, especially when the access control needs to be fairly flexible. Although it’s easy to implement a user interface that directly represents your data model, your users may not always be able to easily use or understand how to accomplish tasks using it. Usability is important to consider when tackling complex concepts or data structures through web UI.

The requirements for our security model were for granting or denying access to specific data elements in the database. By default a user has access to everything. If you explicitly grant access to an element, the user then only has access to those elements you’ve explicitly granted access to. You can also deny access to a given element; however a single element can only have one preference state, un-specified, grant access, or deny access. To top it all off, all the elements are in a recursive tree structure (always makes things more fun).

I had immediately made the decision that whatever we did, it needed to be in a tree fashion to show the end user the structure of what they were granting access to, however the question remained as to how to represent each state in an intuitive and easy to understand way. Enter the 3-State check box. More »

Creating a JavaScript HashTable

I use a lot of configuration and provider driven services and variables for developing web applications. Let’s face it, I don’t like to recompile. I recently had the need to share my Web.config settings with the client code, but didn’t want to declare a variable for every possible setting, I just wanted to dynamically create the script of configuration settings in some collection and have access to that in my client side code. Because I wanted this collection to act just like a HashTable in System.Collections, I decided to create a JavaScript type to mirror the storage and access paradigm of the HashTable for use in my applications. More »

Shrinking JavaScript Arrays

Recently I’ve found myself writing a ton of client code in a new pure JavaScript/WCF project I am working on. Since most of the programming I’m doing for the UI is in JavaScript files, I’ve found myself having to work with the Array object for many different things. The one thing I’ve noticed however, is that you cannot remove an item from a JavaScript array, say, in the middle of the array and have the array size shrink without losing data at either end, however having to check for array_name[i] != null every single time I iterate the array was getting annoying, to say the least. More »

Protecting PDF files in IIS 6 using Forms Authentication

Problem

We have a very simple ASP.NET web site that uses the built in Forms Authentication provider out of the box for users, roles and security. Our internal business customers have hundreds of PDF documents that should only be accessible for specific users or roles within the company. A majority of users that need access to these files are outside the company firewall and do not have VPN access. The site must be hosted on Windows Server 2003 using IIS 6.

Although this problem could be solved in many ways, I wanted to make the site as dynamic as possible since our web master would need to make constant changes to files, structure, etc and we did not want a programmer having to make changes to specific code or a DBA maintaining a database of files, paths, etc. We also wanted to avoid using a network file share to host the files or wrap the site using Plain Text authentication.

The issue is Forms Authentication provides no security on the request stack within IIS 6 as it does in IIS 7. Because we can’t extend this, our files would be wide open to any attacker or malicious employee looking to download the file by figuring out the link or by users who had bookmarked certain files and later after they had been removed from that role, being able to still access them.

The Solution

The solution seemed easy. Some content management systems allow you to store files in databases, or use URL re-writing to accomplish this task, but I wanted something simpler and easier to extend or duplicate in the future. We’re all pretty familiar with IHttpHandler and it seemed since that’s the way the prior, more complex solutions perform this feat more often than not, why not give it a shot for this: More »

Readability, Sub-Queries in LINQ

I’ve been working with LINQ and LINQ to SQL for a while now and I have to say, it definitely makes object enumeration, data access and binding extremely easy and efficient. Even the dynamic SQL it generates using LINQ to SQL is acceptable in efficiency and performance. One thing I noticed however is when you need to do complex sub queries or provide summary information within nested levels of relationships, the code can become pretty messy, until I discovered you can write LINQ statements within a generic type from inside an existing LINQ statement.

I’m sure somewhere in the documentation it says you can do this, but I just discovered it for myself, so no laughing if you’re thinking to yourself, “DUH; what a moron!” More »

You can’t always blame Bill when Vista breaks

Just recently I decided to upgrade my development machine at the office from Windows XP to Windows Vista. Taking into consideration the ability to play around with the new IIS7, as well as take the opportunity to upgrade to Visual Studio 2008 Team Suite. I can say I’m happy that I did, I even did a clean install since Vista Enterprise did not support an upgrade from XP. Then the fun started. After spending a day and a half re-installing all of my development tools, MS Office, hunting down new drivers for the video card, sound card as well as running Windows Updates, etc I was up and running without a care in the world. More »

Checking for a null session is a serious matter

While using Infragistics NetAdvantage for ASP.NET I noticed a bug while working with the UltraGauge (WebGauge) control. It turns out that if you disable session state for the page that this control is on or for the entire web application as I had done for performance reasons, you get a nasty error:

"Session state can only be used when enableSessionState is set to true, either in a configuration file or in the Page directive. Please also make sure that System.Web.SessionStateModule or a custom session state module is included in the <configuration>\<system.web>\<httpModules> section in the application configuration."

It turns out that the logic in Infragistic's source code was not that bad, it tested if the page was null, that we weren't in design mode, and then used this little snippet of code which was throwing the exception:

    "if (this.Page.Session != null) {…"

This may seem like a sane check, and for the life of me it took a while to figure out what the problem was… turns out that if you call the get { } accessor in the Page's Session property, it in turn calls a method, get_Session(), which throws this exception upon not having access to session or a proper provider/handler. While I lodged a bug with Infragistics to put in a fix for this control, I went ahead and searched for a solution myself.

Inheritance is a wonderful thing, and so are virtual properties

The SAFE way to check whether or not it is valid to use session, regardless if you are on a page, control, static class, etc, is to use HttpContext.Current.Session. For example:

if (HttpContext.Current.Session != null)
{
    // do stuff
}

Therefore, we needed to override the Page's default behavior to add a "safe" get for the Session property:

public override HttpSessionState Session
{
    get
    {
        if (HttpContext.Current.Session == null)
            return null;
        else
            return base.Session;
    }
}

By putting this code in my Page's code-behind, I was able allow the WebGauge control to safely check if Session was null through the Page's Session property without this operation throwing an exception. I was also able to circumvent the need for a re-compile or further code changes should I ever want to re-enable session state in my application or even for that page.

Update

Dear Infragistics Customer,

The following WebGauge issue that you reported has been addressed in a hotfix release:
BR29520 – Exception throw when using the WebGauge with FileSystem deployment, and SessionState turned off for the website.

Incident(s):
WeG73

Hotfix Version(s):
7.2.20072.1072 CLR 2.0, 7.3.20073.1046 CLR 2.0, 8.1.20081.2001 CLR 2.0, 8.1.20081.2001 CLR 3.5

 

Introductions

First of all, I have to give a major thanks to the BlogEngine.NET team. Without their amazing contributions to the .NET development community it would have taken me weeks in my spare time to get this blog up and running; that is with ½ the functionality because frankly, like most developers I know, I typically don't have spare time. This site is running off of the latest build, 1.3, and has a custom theme that I created for my own taste, which thanks to the team and the ease of the CSS compliant design, took only a couple of hours of development. If you like it, feel free to download it and use it (with proper credit of course Wink). You can download it here: Waves.zip (462.14 kb).

I have been in software development for the past 8 years, working mainly with Microsoft technologies including VB 6, C#, ASP.NET and more recently AJAX and if time and employer dollars allow, Silverlight. I've been in IT for about 10 years now having served my time on numerous help desks, production support and R & D teams. I am currently working for a home warranty company based out of Denver, CO migrating existing Windows Smart Client applications and back-office automation to the web, mobile space and beyond.

So what am I doing getting a blog so late in the game you might ask? Well, I'm married. As odd of an answer that may seem to be, my 3 girls would tell you that I'm just not cool and this is the first opportunity that I've had amidst my wife studying for the LSATs and my honey-do list is empty that I can spend some quality time on the computer, which I already spend 60 hours a week on; go figure.

In the next week or so I plan on posting my first real entry regarding table locking and transactions while using LINQ to SQL against SQL Server 2000. In the meantime if you want to leave comments on how silly you think blogging is or if you won the lottery or even if you think 80's hair metal bands are the coolest ever, feel free! Also if you want to pose questions or suggestions on possible posts that may divulge my experience in any of the areas you're interested in or have questions please don't hesitate.

Thanks and happy blogging!