Posted by & filed under Web Development.

I am donating my time to rebuild wolvesathletics.com in ASP.NET using DotNetNuke.   It will be a significant upgrade for Timberline High School’s athletics website and offer them better capabilities for editing for coaches and team parents.  Since I am donating the time I didn’t want to hire a designer, so having no formal design experience I gave it a shot.

I am very interested in getting feedback about the design and what I can do to polish it up.  Please leave comments on this with your ideas.

Review the Wolves Athletics design concepts.

Posted by & filed under Web Development.

I spent some of my Labor Day weekend starting to learn Silverlight.  I began when BJ asked me to show him how to program a game.  We started programming a simple Space Invaders style game.  I am going to allow that project to progress at his pace, so I decided to take on a different project to experiment with, a document viewer.

I have been working on a project at work that requires a PDF be embedded in a page, but disallow printing, saving, or copying the document.  We discovered GhostScript’s ability to convert a PDF to a collection of PNG images.  It creates a single PNG file for each page in the PDF.   This allows only the pages that are viewed to be loaded and we don’t have to worry about applying any digital rights management (DRM toolkits are $$$) to the PDF.

The document viewer takes this collection of PNG’s and embeds them into the viewer, so that they can be rotated, zoomed in on, and browsed.

Check out the demo at http://www.aaronkjackson.com/dev/silverlight/DocumentViewer/.

NOTE: The zoom in feature can hide the button bar.  If that happens resize the browser window to a smaller size.  I am working on adding scroll bars to prevent this from happening.

Posted by & filed under Web Development.

While developing AspNetInfo I ran into a styling problem when using jQuery tabs nested in a dialog.  Notice in the dialog how the tab font-size is slightly larger than the tag font-size in the page.

jquery-font-size-example 

This is because the dialog and tab widgets are decorated with the jQuery style .ui-widget, which specifies a relative font-size of 1.3em.

.ui-widget { 
    font-family: Arial,sans-serif; 
    font-size: 1.3em; 
}

The font-size of the nested tab widget ends up being larger due to CSS inheritance and relative font-size.  The tab widget inherits the dialog widget’s relative font-size making the nested tab widget items 1.69em in size (1.3em X 1.3em = 1.69em).

This can be fixed by specifying a more specific rule for the nested tab widget to bring all of it’s items back to 1.3em.  This rule can be applied to just the tabs by specifying the tab id or to all instances of nested widgets.

Fix for email tab only:

#emailTabs.ui-widget {
    font-size: 1em;
}

Fix for all widgets:

.ui-widget .ui-widget {
    font-size: 1em;
}

Posted by & filed under Web Development.

This week one of our database servers was upgraded to a 64bit Windows platform.  Everything seemed fine until I went to execute an SSIS package.   I opened the package with dtexecui.exe and received the following gift after hitting the execute button.

The new connection manager could not be created.
Additional information: Exception from HRESULT: 0xC0010014
(Microsoft.SQLServer.DTSRuntimeWrap)

After much searching, installing Business Business Intelligence Development Studio (BIDS) to debug, and heartache I ended up finding a form post entitled “MS SQL 2005 SP2 x64 & SSIS Packages” about several key DLLs that may not have been properly registered at setup.  This saved my day!  I registered the problem child DLL using the following command and life was good again.

regsvr32 "\Program Files (x86)\Microsoft SQL Server\90\DTS\Binn\DTS.dll"

Posted by & filed under Web Development.

To help make writing and maintaining JavaScript easier in ASP.NET I have started to use a pattern that isolates the JavaScript variables away from the core script.  By doing this I can avoid a bunch of string concatenation in my server side code and embedded code blocks in my .aspx page when rendering dynamic JavaScript.  The core JavaScript can be placed into a .js file.  The ASP.NET page is now only responsible for rendering a list of updated variables that the core script expects.

To demonstrate consider a set of jQuery tabs that contains forms on each tab.  When a form is submitted from a particular tab the tab should be selected after the form posts back.  Using embedded code blocks the JavaScript would be. 

<script type="text/javascript">
    jQuery(function($) {
        $("#tabs").tabs();
        $("#tabs").tabs('select', <%=selectedTab %>);
    });
</script>

While this looks pretty clean it prevents us from putting this JavaScript into a .js file.  Applying the variable pattern the JavaScript can be refactored to the following and placed into a .js file.

jQuery(function($) {
    $("#tabs").tabs();
    $("#tabs").tabs('select', selectedTab);
});

The page is now only responsible for rendering the ‘selectedTab’ variable.

<script type="text/javascript">
    var selectedTab = 3;
</script>

I have created a JavaScriptVariable class to assist in rendering the JavaScript variables.   The JavaScript block is rendered to the page using ScriptManager.RegisterStartupScript to ensure the variable are available to scripts.  In addition, the ‘JavaScriptVariables’ member variable and the RenderJavaScriptVaraibles() method could be added to a base Paqe class.  Here is an example using JavaScriptVariable to render the variables for example above.

    IList<JavaScriptVariable> JavaScriptVariables = new List<JavaScriptVariable>();
    protected override void OnPreRender(EventArgs e)
    {
        base.OnPreRender(e);
        JavaScriptVariables.Add(new JavaScriptVariable("selectedTab", selectedTab.ToString(), "{0}"));
        ScriptManager.RegisterStartupScript(this, typeof(AspNetDiag), "AspNetDiagVars.js", RenderJavaScriptVariables(), true);
    }

    private string RenderJavaScriptVariables()
    {
        StringBuilder js = new StringBuilder();
        foreach (var jsVar in JavaScriptVariables)
        {
            js.AppendFormat("var {0} = {1};", jsVar.Name, jsVar.GetFormatedValue());
        }
        return js.ToString();
    }

Finally the source for JavaScriptVariable.  

class JavaScriptVariable
{
    public string Name { get; set; }
    public string Value { get; set; }
    public string Format { get; set; }

    public JavaScriptVariable(string name, string value) : this(name, value, "\"{0}\"") { }
    public JavaScriptVariable(string name, string value, string format)
    {
        Name = name;
        Value = value;
        Format = format;
    }

    public string GetFormatedValue()
    {
        return String.Format(Format, Value);
    }
}

Posted by & filed under Web Development.

ASP.NET web forms page have a JavaScript method for handling PostBacks called “__doPostBack”.  This function is used to submit button clicks back to the server.

function __doPostBack(eventTarget, eventArgument) {
    if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
        theForm.__EVENTTARGET.value = eventTarget;
        theForm.__EVENTARGUMENT.value = eventArgument;
        theForm.submit();
    }
}

The cool thing is that you can take advantage of the same methods that the framework uses to generate javascript for button clicks.  Use the following in your code file to generate the JavaScript that performs the PostBack. Using this method will ensure that the proper ClientID for the control is used.

protected string GetLoginPostBack()
{
    return Page.ClientScript.GetPostBackEventReference(btnLogin, string.Empty);
}

Then in the ASPX page add a javascript block.

<script language="javascript">
function btnLogin_Click() {
  <%= GetLoginPostBack() %>;
}
</script>

The final javascript will be rendered like this.

<script language="javascript">
function btnLogin_Click() {
  __doPostBack('btnLogin','');
}
</script>

Now you can use “btnLogin_Click()” from your javascript to submit the button click to the server.

Posted by & filed under Web Development.

I ran into some nasty SQL today while updating a report at work.  The report accepted several parameters that were optional.  When a parameters value was set to ‘ALL’ then the filter was ignored.   To handle the optional parameters the previous developer had created a set of WHERE statements for each scenario that the parameters could exist as.  Here is the WHERE clause in question.  Each scenario is separated by ‘OR ( BP.BS_Paid = 1 )’.  Good thing there were only three optional parameters.

The nasty WHERE clause: (bear with me on the names in the SQL.  The snippet is from a health care application.)

WHERE   ( BP.BS_Paid = 1 )
        AND ( FTProc.Description = 'BreastProcedureName' )
        AND ( BP.BS_Performed_Date BETWEEN @ProcedurePerformed_From
                                   AND     @ProcedurePerformed_To )
        AND ( SUBSTRING(PS.Site_num, 2, 2) = REPLICATE('0', 2 - LEN(@LCC))
              + @LCC )
        AND ( PS2.Site_num = @Provider )
        OR ( BP.BS_Paid = 1 )
        AND ( FTProc.Description = 'BreastProcedureName' )
        AND ( SUBSTRING(PS.Site_num, 2, 2) = REPLICATE('0', 2 - LEN(@LCC))
              + @LCC )
        AND ( PS2.Site_num = @Provider )
        AND ( @ProcedurePerformed_ALL = 'ALL' )
        OR ( BP.BS_Paid = 1 )
        AND ( FTProc.Description = 'BreastProcedureName' )
        AND ( BP.BS_Performed_Date BETWEEN @ProcedurePerformed_From
                                   AND     @ProcedurePerformed_To )
        AND ( PS2.Site_num = @Provider )
        AND ( @LCC = 'ALL' )
        OR ( BP.BS_Paid = 1 )
        AND ( FTProc.Description = 'BreastProcedureName' )
        AND ( PS2.Site_num = @Provider )
        AND ( @ProcedurePerformed_ALL = 'ALL' )
        AND ( @LCC = 'ALL' )
        OR ( BP.BS_Paid = 1 )
        AND ( FTProc.Description = 'BreastProcedureName' )
        AND ( BP.BS_Performed_Date BETWEEN @ProcedurePerformed_From
                                   AND     @ProcedurePerformed_To )
        AND ( SUBSTRING(PS.Site_num, 2, 2) = REPLICATE('0', 2 - LEN(@LCC))
              + @LCC )
        AND ( @Provider = 'ALL' )
        OR ( BP.BS_Paid = 1 )
        AND ( FTProc.Description = 'BreastProcedureName' )
        AND ( SUBSTRING(PS.Site_num, 2, 2) = REPLICATE('0', 2 - LEN(@LCC))
              + @LCC )
        AND ( @ProcedurePerformed_ALL = 'ALL' )
        AND ( @Provider = 'ALL' )
        OR ( BP.BS_Paid = 1 )
        AND ( FTProc.Description = 'BreastProcedureName' )
        AND ( BP.BS_Performed_Date BETWEEN @ProcedurePerformed_From
                                   AND     @ProcedurePerformed_To )
        AND ( @LCC = 'ALL' )
        AND ( @Provider = 'ALL' )
        OR ( BP.BS_Paid = 1 )
        AND ( FTProc.Description = 'BreastProcedureName' )
        AND ( @ProcedurePerformed_ALL = 'ALL' )
        AND ( @LCC = 'ALL' )
        AND ( @Provider = 'ALL' )

This mess begged to be refactored, so I sketched out my problem on the white board in the office and got some input from the team.  We came up with three techniques for handling optional parameters.

Technique #1. WHERE clause if..then

This technique essentially uses the an OR operator to decide if the parameter is missing.   When the first expression evaluates to true then the second expression is ignored making the parameter optional.

Using this technique the WHERE clause can be refactored to the following.

WHERE    BP.BS_Paid = 1  
         AND FProc.TypeID = 13
         AND (@Provider = 'ALL' OR PS2.Site_num = @Provider)
         AND (@ProcedurePerformed_ALL = 'ALL' 
              OR (BP.BS_Performed_Date > @ProcedurePerformed_From 
                  AND BP.BS_Performed_Date < @ProcedurePerformed_To))
         AND (@LCC = 'ALL' 
              OR SUBSTRING(PS.Site_num, 2, 2) = REPLICATE('0', 2 - LEN(@LCC))+ @LCC ))

The WHERE clause is much more maintainable in this version.  In addition,  the filter can use complex expressions, such as, date ranges.

Technique #2. ISNULL or COALESCE operators

This technique requires that the parameter be NULL when ignoring optional parameters.   The COALESCE operator will use the first NON NULL value.  When a parameter is NULL then the COALESCE uses the column’s value as the second expression, there by setting the column equal to its self.

This technique works fine when evaluating expressions with ‘=’ operator.  However, using the ‘<>’ operators don’t work when comparing a column to itself.   I was forced to comment out the date range expressions are a result of this limitation.

Here is the results from using this technique.

WHERE    BP.BS_Paid = 1  
        AND FProc.TypeID = 13
        AND dbo.GetLCCFromSite(PS.Site_num) = COALESCE(@LCC, dbo.GetLCCFromSite(PS.Site_num))
--      AND (BP.BS_Performed_Date > COALESCE(@ProcedurePerformed_ALL,@ProcedurePerformed_From)
--      AND BP.BS_Performed_Date < COALESCE(@ProcedurePerformed_ALL,@ProcedurePerformed_To))
        AND PS2.Site_num = COALESCE(@Provider,  PS2.Site_num)

Technique #3. Dynamic query using sp_executesql

This technique builds a SQL query on the fly and then executes it using sp_executesql.   Dynamically building the SQL allows for WHERE expressions to be omitted all together from the query.  The IF….ELSE construct is used to determine if optional parameters should be included in the query.  I am speculating that this is the best performing technique, because parameters are not even included in the query.

DECLARE @SQLString nvarchar(500);
DECLARE @ParmDefinition nvarchar(500);

SET @SQLString = N'WHERE BP.BS_Paid = 1 AND FProc.TypeID = 13';
IF @Provider != 'ALL'
BEGIN
    SET @SQLString = @SQLString + N' AND PS2.Site_num = @xProvider';
END
IF @ProcedurePerformed_ALL != 'ALL'
BEGIN
    SET @SQLString = @SQLString + N' AND (BP.BS_Performed_Date > @xProcedurePerformed_From AND BP.BS_Performed_Date < @xProcedurePerformed_To))';
END
IF @ProcedurePerformed_ALL != 'ALL'
BEGIN
    SET @SQLString = @SQLString + N' AND SUBSTRING(PS.Site_num, 2, 2) = REPLICATE(''0'', 2 - LEN(@xLCC))+ @xLCC ))';
END

SET @ParmDefinition = N'@@xProvider NVARCHAR(10)
                        ,@xProcedurePerformed_From DATETIME
                        ,@xProcedurePerformed_To DATETIME
                        ,@xLCC INT';

EXECUTE sp_executesql @SQLString, @ParmDefinition
                      ,@Provider
                      ,@ProcedurePerformed_From 
                      ,@ProcedurePerformed_To
                      ,@LCC;

Posted by & filed under Web Development.

The primary purpose of this blog is to help me catalog stuff that I find useful. I wanted a good way to highlight code snippets as well as make them downloadable when I want to reuse them. Thanks to this great post on hanselman.com I found Syntax Highlighter. Syntax Highlighter will decorate <pre></pre> tags that have been marked with specific CSS classes using JavaScript.  There is no need to have to include HTML markup in the code.   How great is that?!

Here is a test snippet:

function test() : String
{
	return 10;
}

Posted by & filed under MidField, Web Development.

I am preparing to start my next “programming for fun” project which will be a portal for high school athletics departments. It’s a domain I know a bit about since I have already built a one-off portal for Timberline High School called wolvesathletics.com. I built wolvesathletics.com at a time in my career when was poking around in the Java web development stack. The site was built on Struts, Hibernate, and Spring and with a small amount of support has been running for the past couple of years.

In that couple of years I have done nearly all of my development in the Microsoft development stack and DotNetNuke. I have found value in the traditional Microsoft ASP.NET approach and will continue using it when it makes sense. However with ASP.NET MVC, nHibernate, and StructureMap on the .NET scene I am looking forward to revisiting some familiar development patterns and getting exposure to many new ones.

I am pleased to introduce, MidField, a portal and social network for high school athletic departments. My first steps will be to perform a competitive analysis, identify personas, and user stories. I continue to post my progress and pit falls here.