I've finally gotten around to using something from the AJAX Control Toolkit in an actual project. My client was dissatisfied with the <asp:calendar> control so I offered to AJAX enable the site and replace it with the fancier Calendar control from the ASP.NET AJAX Control Toolkit. Naturally the client found something he wanted to work a little different. This calendar control was for entering your birth date and he did not want the user to scroll back decades to find that date. He wanted the calendar to show up with the 1990-1999 decade already visible so the user could start from there. Fortunately I remembered that the ASP.NET AJAX Control Toolkit comes with all the source code so you can customize it to suite your needs.

This requirement was extremely easy to implement. All you really need to do is set the calendar mode to "years" when you first show it. However there was no property for initial mode so I had to create one. This was virtually a cut and paste hack because there are existing properties to base it on.

1. Open CalendarExtender.cs and create a new ExtenderControlProperty:

   1: [DefaultValue("")]
   2: [ExtenderControlProperty]
   3: [ClientPropertyName("initialMode")]
   4: public virtual string InitialMode
   5: {
   6:    get { return GetPropertyValue("InitialMode", string.Empty); }
   7:    set { SetPropertyValue("InitialMode", value); }
   8: }

2. Open CalendarBehavior.js and create a new member:

   1: this._initialMode = null;

3. Also in CalendarBehavior.js add new get and set functions for the property access:

   1: get_initialMode : function() { 
   2:     /// <value type="String">
   3:     /// The initial mode of the calendar
   4:     /// </value>
   5:  
   6:     return this._initialMode; 
   7: },
   8: set_initialMode : function(value) { 
   9:     if (this._initialMode != value) {
  10:         this._initialMode = value; 
  11:         this.raisePropertyChanged("initialMode");
  12:     }
  13: }, 

4. And finally set the _switchMode in the show : function() with this new line of code:

   1: this._switchMode(this._initialMode, true);

Compile the AjaxControlToolkit project and copy the AjaxControlToolkit.dll file to your bin directory. Now you can use your new property in the Calendar control like so:

   1: <ajaxToolkit:CalendarExtender ID="calendarButtonExtender" runat="server" TargetControlID="Date5" 
   2:             PopupButtonID="Image1" InitialMode="years" />
Calendar-Years-Mode[4]

I'm finally working on a project with the potential to be a really high profile web site. I've offered my services as a volunteer programmer to the http://www.vloggerheads.com web site which is being built on the Ning social networking platform. This site is an attempt by prominent vloggers from YouTube and LiveVideo to take control of their community.

Vloggers have been plagued by trolls, hackers, haters, and cyberbullies who are allowed to run amuck on the video sharing sites. This has been a major problem for a very long time and the sites where people vlog have ignored the frequent complaints from their users. Vloggers feel unappreciated. They don't think the video sharing sites are interested in creating a safe environment for the community. I've been outraged over the shoddy customer service and total indifference to the user base for quite some time. YouTube is like a convenience store in a bad section of town where the business owner allows hoodlums to lounge outside the store and harass its customers. The hoodlums are even allowed inside the store to give the customers grief as they shop and a hoodlum may even become customer of the month. Trolls have been featured on YouTube!

This has led to a revolt among the user base. It is an inspiring example of the collaboration that social networking is said to foster. Vloggers have come together to plan their own video sharing site that will provide a safe environment to do what they love to do. Personally, if I was managing a web site and my user base left en masse to form their own site out of disgust with how I was running things, I would feel professionally mortified.

The Ning social networking platform is surprisingly customizable. They provide more than the usual XML and JSON data feeds as an API. You can actually script your site in PHP. They don't use a proper database though. You have to add custom developer attributes to a set number of content objects to extend their data schema. Ning rolled their own Model View Controller framework. My brief study of CakePHP was useful in understanding this architecture but I still need to brush up on my PHP. Ning also uses the Dojo JavaScript toolkit which is worth studying. So far I have learned enough on this project to make it well worth my time.

As far as ASP.NET goes, the only interesting aspect to the project so far has been using PHP as a SOAP client to an ASP.NET web service. This proved to be tricky because you must specify the data type of the parameters in PHP and send them as an associative array.

Although the Ning site has energized the community by providing it with a sense of ownership and control, there is still an awareness that basing the site on Ning could be limiting. Nobody wants to be at the mercy of another indifferent social networking site that will not enforce its terms of service. I've already recommended http://www.codeplex.com/videoshow as a potential vlogger platform but it lacks any social networking features and I don't relish the prospect of building that from scratch.

I regularly browse the ASP.NET Weblogs for hot tips so when Hosam Kamel and Jose R. Guay Paz announced the release of the SQL Server 2005 Driver for PHP I decided to give it a try.

The download includes a compiled help file SQLServerDriverForPHP.chm with installation instructions and sample code. I won't repeat anything you can already find there but below is a screen shot of a new section that appears when you call phpinfo:

I already had some sample code to export data from SQL Server to JSON using PHP so I just converted it to use this new driver:

   1: /* Specify the server and connection string attributes. */
   2: $serverName = "(local)";
   3: $connectionInfo = array( "UID"=>"sa",
   4:                          "PWD"=>"password",
   5:                          "Database"=>"Northwind");
   6:                          
   7: /* Connect using SQL Server Authentication. */
   8: $conn = sqlsrv_connect( $serverName, $connectionInfo);
   9: if( $conn === false )
  10: {
  11:      echo "Unable to connect.</br>";
  12:      die( print_r( sqlsrv_errors(), true));
  13: }
  14:  
  15: $tsql = "SELECT * FROM Customers";
  16: $stmt = sqlsrv_query( $conn, $tsql);
  17: if( $stmt === false )
  18: {
  19:      echo "Error in executing query.</br>";
  20:      die( print_r( sqlsrv_errors(), true));
  21: }
  22: $data = "["; 
  23: while($row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_ASSOC))
  24: {
  25:     $data = $data . json_encode($row) . ", ";
  26: }    
  27: $data = $data . "]";   
  28: echo $data;
  29:  
  30: /* Free statement and connection resources. */
  31: sqlsrv_free_stmt( $stmt);
  32: sqlsrv_close( $conn);
NOTE: The code snippit plug-in does not support PHP code so you get no syntax highlighting.

Since we have not moved to Visual Studio 2008 at work, I have been unable to keep up with the progress in ASP.NET technology. I can't get into Silverlight 2.0 or ASP.NET MVC without Visual Studio 2008. 

I won't be blogging much here for awhile because I'm studying CakePHP and Flash which have nothing to do with ASP.NET. CakePHP is an attempt to bring MVC to the PHP community. Sometimes CakePHP seems half-baked to me. Sorry, I could not resist that joke. Actually CakePHP is a very promising way to rapidly prototype web applications. By studying CakePHP I'll get many of the concepts behind Model View Controller. I'm really not interested in architectural patterns used in software engineering but MVC takes a lot of the drudgery out of web development and even I can appreciate that. At the very least, you can use it to get a basic CRUD application up and going in minutes. CakePHP supports scaffolding and unit testing. I imagine it is based on Ruby On Rails and emulates many Rail features but I'm more familiar with PHP than Ruby.

I'm studying Flash because it is used for animation. There is a lot of material available on how to animate in Flash. Ultimately I may do all my animation in After Effects though because it is far more versatile than Flash. Flash animation is only the standard for online animation because its vector graphics make it light weight. However, if you are doing all your animation for video then there is less reason to use Flash. Flash is also used to deliver video on the Internet and I'm heavily involved in online video so I should learn all aspects of the technology.

There are some interesting features in Flash that designers don't seem to be taking advantage of. For instance, there is a web service component for Flash but I have not seen many web service clients done in Flash. You can also automate the Flash authoring application using JavaScript and I suspect very little has been done with that.

Over the weekend I went to Philadelphia for a YouTube gathering. I shot lots of footage of historical sites and colonial buildings. This gives me plenty of material to use for my editing experiments.

I've been exploring the world of the web designer and noticed that ASP.NET does not exist in that world. I've been reading web design blogs and browsing through articles on http://www.designfloat.com/, a sort of DIGG site for the design community, and I don't encounter any mention of ASP.NET at all.

I have observed that web designers are somewhat aware of PHP because they are heavily involved in developing custom themes for WordPress. Creating skins and themes for open source web applications seems to be a good gig for web designers. But a lot of the attention is on WordPress, Joomla, and OsCommerce. I don't find any articles, guides, or other resources on designing for DotNetNuke or ASP.NET Master Pages, etc. Of course, I could find that through a targeted search but I'm trying to get a overall sense of what the design community is focused on.

Web designers are urged to increase their "coding skills" but this usually means CSS and XHTML.  They are not pressured to learn PHP and they certainly aren't being asked to know anything at all about C# or VB.NET or even ASP.NET.

It is not clear why web designers are so ignorant of ASP.NET. The complete absence of any mention of ASP.NET means there is also an absence of criticism. It could be that ASP.NET was dismissed by the design community because it fails to generate HTML code that meets the design community's standards, i.e. layout through CSS rather than tables, cross browser support, etc. Of course, you can solve some of these problems with the CSS Friendly Control Adapters but that is too technical for a web designer. I suspect ASP.NET is too technical in general for web designers. They are very adverse to code and programming.

On the other hand, the ASP.NET community is surprisingly focused on esoteric programming and software engineering topics. I wonder if this explains why ASP.NET initially had such poor support for proper CSS layout and browser compatibility? The engineer mindset seems to govern its development rather than a pure web developer's perspective.

Since I am not an ASP.NET evangelist it does not trouble me that web designers aren't interested in ASP.NET. From my perspective this just means there may be an opportunity here to bridge the gap. I have had easy projects that merely involved applying a design to an ASP.NET web site because the designer couldn't do it without messing things up. Web designers do have a lot of trouble working with ASP.NET. They don't understand a page directive and they delete web controls that are referenced in the code behind, causing the familiar "Object reference not set to an instance of an object" error which baffles them. I'm considering a transition from programming to web design and I suspect I would find the least competition in developing DotNetNuke skins.

The web design community is not preparing for Silverlight. I did not come across any mention of Silverlight or Expression Blend while idly browsing web design articles and topics. Of course, if you are totally uninterested in ASP.NET then you are not going to be following the developments in Silverlight. This may create a brief opportunity in a tight market for Expresion Blend designers. I'm not a technology or business pundit so I'm not going to speculate on the fortunes of Microsoft's technology bids. I'm actually studying Flash right now, not Silverlight, because Flash has become very important for online video and Flash is used for a lot of animation which is a type of content I could create.

I plan to continue to infiltrate the web design community and gauge their interest in ASP.NET and Silverlight. It may be advantageous for me to collaborate with a professional web designer and get some feedback on my efforts to apply design to ASP.NET web sites.

I have created an ASP.NET page to automate the Microsoft Source Code Analyzer for SQL Injection command line tool. It would be tedious to craft a command for every page in a large Classic ASP web site. I was unable to scan my entire site until I developed this ASP.NET page.

Why an ASP.NET page and not a console application? Well "I've learned to use a hammer, so I'm gonna hammer everything" as Jeff Atwood would say. LOL. But seriously, I wanted to generate a HTML report so it may as well be a single ASP.NET page. You can easily convert it to a console application or even a Windows application. I did learn how to redirect standard input, output, and error streams which is good to know.

msscasi.aspx

   1: <%@ Page Language="C#" Theme="Granite" MasterPageFile="~/AppMaster.master" AutoEventWireup="true" CodeFile="msscasi.aspx.cs" Inherits="msscasi" Title="ASP Web Site Parser" %>
   2: <asp:Content ID="Content1" ContentPlaceHolderID="mainCopy" Runat="Server">
   3:     <div class="container">
   4:         <h2>ASP Web Site Parser</h2>
   5:         <p class="teaser">
   6:             Scans all ASP pages in a web site for SQL Injection vulnerabilities.</p>
   7:         <p>Enter ASP site file location:&nbsp;<asp:TextBox ID="txtPath" runat="server"></asp:TextBox></p>            
   8:         <p><asp:Button ID="btnSubmit" Text="Submit" runat="server" OnClick="btnSubmit_Click" /></p>
   9:         <p><asp:Label ID="lblMessage" runat="server"></asp:Label></p>
  10:         <p><asp:Label ID="lblErrorMessage" ForeColor="red" runat="server"></asp:Label></p>
  11:     </div>        
  12: </asp:Content>
  13: <asp:Content ID="Content2" ContentPlaceHolderID="leftColumn" Runat="Server">
  14: </asp:Content>
  15: <asp:Content ID="Content3" ContentPlaceHolderID="rightColumn" Runat="Server">
  16: </asp:Content>

msscasi.aspx.cs

   1: using System;
   2: using System.Data;
   3: using System.Configuration;
   4: using System.Collections;
   5: using System.Web;
   6: using System.Web.Security;
   7: using System.Web.UI;
   8: using System.Web.UI.WebControls;
   9: using System.Web.UI.WebControls.WebParts;
  10: using System.Web.UI.HtmlControls;
  11: using System.IO;
  12: using System.Diagnostics;
  13: using System.Text;
  14:  
  15: public partial class msscasi : System.Web.UI.Page
  16: {
  17:  
  18:     StringBuilder sbStandardOutput = new StringBuilder();
  19:     StringBuilder sbStandardError = new StringBuilder();
  20:     public const string MSSCASI_PATH = "\"G:\\msscasi\\msscasi_asp.exe\"";
  21:  
  22:     /// <summary>
  23:     /// Handles the Click event of the btnSubmit control.
  24:     /// </summary>
  25:     /// <param name="sender">The source of the event.</param>
  26:     /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
  27:     protected void btnSubmit_Click(object sender, EventArgs e)
  28:     {
  29:         if (String.IsNullOrEmpty(txtPath.Text))
  30:         {
  31:             lblErrorMessage.Text = "You neglected to enter a file path to the ASP site!";
  32:             return;
  33:         }
  34:         else
  35:         {
  36:             // proceed with recursive file processing
  37:             try
  38:             {
  39:                 DirectoryInfo objDirectoryInfo = new DirectoryInfo(txtPath.Text);
  40:                 ListDirectoryFiles(objDirectoryInfo);
  41:                 lblMessage.Text = sbStandardOutput.ToString();
  42:                 lblErrorMessage.Text = sbStandardError.ToString();
  43:                 lblErrorMessage.Visible = true;
  44:  
  45:                 // write a report to a file as well
  46:                 FileInfo objFileInfo = new FileInfo(Server.MapPath("App_Data\\report.html"));
  47:                 StreamWriter objStreamWriter = objFileInfo.CreateText();
  48:                 objStreamWriter.Write(sbStandardOutput.ToString());
  49:                 objStreamWriter.Flush();
  50:                 objStreamWriter.Close();
  51:                 objStreamWriter.Dispose();
  52:             }
  53:             catch (Exception err)
  54:             {
  55:                 // display error
  56:                 lblErrorMessage.Text = err.ToString();
  57:                 lblErrorMessage.Visible = true;
  58:             }
  59:  
  60:         }
  61:     }
  62:  
  63:     /// <summary>
  64:     /// Lists the directory files.
  65:     /// </summary>
  66:     /// <param name="objDirectoryInfo">The obj directory info.</param>
  67:     /// <remarks>This is a recursive function.</remarks>
  68:     public void ListDirectoryFiles(DirectoryInfo objDirectoryInfo)
  69:     {
  70:         string strGlobalAsa = "";
  71:         // loop through files
  72:         foreach (FileSystemInfo objFileSystemInfo in objDirectoryInfo.GetFileSystemInfos())
  73:         {
  74:             if (objFileSystemInfo is FileInfo)
  75:             {
  76:                 FileInfo objFileInfo = ((FileInfo)objFileSystemInfo);
  77:                 if (objFileInfo.Extension == ".asp" || objFileInfo.Extension == ".asa")
  78:                 {
  79:                     // determine the file path to the global.asa file
  80:                     if (objFileInfo.Name.ToLower().Trim() == "global.asa")
  81:                     {
  82:                         strGlobalAsa = objFileInfo.FullName;
  83:                     }
  84:                     // shell command
  85:                     System.Diagnostics.Process objProcess = new System.Diagnostics.Process();
  86:                     objProcess.StartInfo.FileName = MSSCASI_PATH;
  87:                     objProcess.StartInfo.Arguments = "/GlobalAsaPath=" + strGlobalAsa;
  88:                     objProcess.StartInfo.Arguments = "/input=" + objFileInfo.FullName;