Pennsylvania has not passed a budget for over two months. I was laid off from my full time job because of that. Now that I am collecting unemployment, I’ve had enough spare time to learn French. I have read five books on the French language. I think learning French is more worthwhile than learning Silverlight!

I can read enough French to explore French web sites. The French version of Wikipedia is especially useful in expanding my vocabulary. I also watch a home shopping channel via streaming video because the French spoken on that channel is very clear.

If Pennsylvania does not pass a budget soon I will have time to learn German too!


Pennsylvanie n'a pas passé un budget (ses dépenses en fonction de) depuis plus de deux mois. J'ai été licencié de mon emploi à temps plein à cause de cela. Maintenant que je suis la collecte de chômage, j'ai eu assez de temps libre pour apprendre le français. J'ai lu cinq livres sur la langue française. Je pense que l'apprentissage du français est plus intéressant que d'apprendre Silverlight!

Je peux lire assez de français pour explorer les sites Internet français. La version française de Wikipédia est particulièrement utile pour élargir mon vocabulaire. Je regarde aussi un chaîne de téléachat via le streaming vidéo, car le français parlé sur ce chaîne est très claire.

Si la Pennsylvanie ne passe pas d'un budget bientôt puis j'aurai le temps d'apprendre l'allemand aussi!

I’ve been having a problem with Windows Live Writer after I installed a WordPress plugin, Now Reading. That plugin allows me to show the books I’m currently reading on the sidebar.

Windows Live Writer-Error

If I have that plugin enabled, I would get the error above, “Invalid Server Response – The response to the blogger.getUsersBlogs method received from the blog server was invalid: Invalid response document returned from XmlRpc server”. Many people have encountered that error and I was able to find several solutions but none of them fixed my problem. Being a rock star programmer, I decided that I would lick this problem and continue to use my plugin with Windows Live Writer. I believe in bending computers to my will instead of living with their problems.

In plain English the error message means the XML response from WordPress does not validate because it is not valid XML. I don’t know why they could not say that in the error message. You can tell it was written by a Microsoft employee!

In order to troubleshoot this problem you need to see the XML response. I did find a XML-RPC debugger at:  http://gggeek.raprap.it/debugger/ but it is not very helpful when the XML is malformed. It can give you some insight into the methods that are available though. In order to figure out exactly what was going on, I wrote a simple VBScript to submit a POST request to the xmlrpc.php file and saved the response to a file. That’s right, I used VBScript! VBScript is perfect for simple tasks that do not warrant a lot of effort.

   1: ' #################################################
   2: ' # VBScript To Call WordPress XMLRPC             #
   3: ' # Need to examine XML response to troubleshoot  #
   4: ' # programmed by Robert S. Robbins on 06/10/2009 #
   5: ' #################################################
   6:  
   7: Set oXMLHTTP = WScript.CreateObject("MSXML2.XMLHTTP")
   8: oXMLHTTP.open "POST", "http://www.williamsportwebdeveloper.com/cgi/wp/xmlrpc.php",False
   9:  
  10: oXMLHTTP.setRequestHeader "Content-Type", "text/xml"
  11: 'oXMLHTTP.send "<?xml version='1.0'?><methodCall><methodName>system.listMethods</methodName><params></params></methodCall>"
  12: oXMLHTTP.send "<?xml version='1.0'?><methodCall><methodName>demo.sayHello</methodName><params></params></methodCall>"
  13:  
  14: 'MsgBox oXMLHTTP.responseText,vbInformation, "XMLRPC Response"
  15:  
  16: Set fso = WScript.CreateObject("Scripting.FileSystemObject")
  17: strWorkingDirectory = Left(WScript.ScriptFullName, InStrRev(WScript.ScriptFullName,"\")-1)
  18: ' unicode format designator -1 solves the "Invalid procedure call or argument" error
  19: Set objOutputFile = fso.CreateTextFile(strWorkingDirectory & "\wp-response.xml", True, -1)
  20: objOutputFile.Write oXMLHTTP.responseText
  21: Set objOutputFile =  Nothing
  22:  
  23: MsgBox  "Done Processing!"

This script calls a XmlRpc method, it does not matter which one, and saves the result to a file. I was able to determine that the XML was invalid because 2 characters where truncated from the end of the last tag.

I’m not exactly sure why two characters get truncated with that plugin enabled but I did find the closing tag in the class-IXR.php file in the wp-includes directory. This file uses a XML template contained within within a nowdoc string, a PHP string that is not parsed. Apparently this is a PHP version of the <![CDATA[ ]]> construct but is meant to exclude quotes from parsing. Anyway, I was able to solve my problem by adding two more line breaks before the closing EOD;. This may not be the only problem with your XML. I also had a problem with a BOM (Byte Order Mark) that Microsoft Expression Web sneakily added to a PHP file I edited (Thanks, Expression Web, that was real sly of you). But I recently upgraded WordPress and I only had to apply my hack to the class-IXR.php file to get Windows Live Writer to accept the XML response from my WordPress blog.

My vacation in Paris, France was a great success and fulfilled one of my dreams. You can read about my travels on my personal blog at: http://williamsportwebdeveloper.com/cgi/wp/

I’ve decided to learn French as a second language even though I did not need to know any French in Paris. Learning a foreign language requires a huge commitment of time and effort, far more than is necessary to learn a programming language. You need a really good reason to learn a second language. As a programmer I am all too familiar with the temptation to learn many computer languages which you’ll never actually use. It can be a waste of time to learn a programming language. I’ve already decided that life is too short to learn Java.

It is actually quite hard to think of a good reason to learn French. Most of the reasons given for studying French as a second language don’t make any sense, especially if you don’t plan to move to France. For example, it does not matter how influential France is as a nation. You don’t need to know French to follow the international news relating to French foreign policy. You also don’t need to know French to vacation in France. That may infuriate the French, but it doesn’t make sense to spend years learning a language just so you can use it for one week when you’ll really need it, occasionally.

The main reason I’ve decided to learn French is to explore the uncharted territory of their geek culture. It may surprise you to learn that there is such a thing as the French geek. The stereotype of the French as artists and intellectuals conceals a far more extensive culture. The French also love comic books, science fiction, horror, video games, and pop music. Their comic book industry, known as bandes dessinées or BD for short, rivals the Japanese manga but is virtually unknown here in the United States. I was in a Borders bookstore last week and saw an entire aisle devoted to Japanese manga in paperback books called tankōbon. There was a smaller bookshelf for Marvel, DC, and other American graphic novels. However I did not find a single bandes dessinées at Borders.

In addition to an unexplored world of graphic novels, the French also publish many science fiction novels which are never translated into English. Some of this science fiction uses historical references to the reign of Louis XIII and the periods of French Baroque and Classicism in a way that is really bizarre and amusing. There are also spy novels and other forms of pulp fiction that will never be shared with the Anglosphere (i.e. the totality of (English-speaking) nations).

I think it would be fun to explore this world of trashy French culture because it goes against the stereotype of the French as sophisticated snobs. I’ve become pretty bored with American culture and its predictable output.

So what does this have to do with programming? Well, programmers are often geeks so I’m staying within my culture with this new obsession. I also intend to visit many more French web sites and I’ll keep an eye out for any innovative uses of technology that have not made it to the English Internet. 

I’m going to Paris France for my vacation this year! I’m very excited about it because I’ve always been a bit of a Francophile. Unfortunately, I don’t speak French so, being a IT professional, I’ve sought a technological solution for the language barrier. I’m not sure that I’ll need to speak any French because I’m going on a guided tour which should reduce my interaction with the locals.

I’ve already blogged about ASP.NET’s support for internationalization and browser languages on my WordPress blog at: ASP.NET 2.0 Culture – Web Site Internationalization. I also blogged about Elgg’s support for languages at Elgg Languages. I’ve done some additional research since then into how PHP supports internationalization and I looked at how all the browsers implement language settings.

Firefox and Opera are the best browsers to use if you are working on making a web site international because they are the only browsers that allow you to indicate the browser language in the user agent string. In Firefox:

  1. To change the browser language type about:config in the address bar and press Enter.
  2. Enter general.useragent.locale in the Filter textbox.
  3. Change en-US to fr-FR or change it back to en-US.

However, I don’t know of a single web site that attempts to detect the browser language by checking the user agent string which will almost always indicate en-US even when your browser language is not set to that. Even with my browser language set to fr-FR, only Google, Microsoft, and Facebook accommodated me with French text. There seems to be some debate over whether it is a good idea to detect browser language settings. Some developers argue that providing content in the appropriate language based on the browser language is the proper way to handle internationalization while others argue that you need to give visitors a means to explicitly change the language using flags because it has become the expected method. In my opinion, you should use both methods because a bilingual visitor will not want to be stuck with the version of the site that matches his browser language settings.

Internet Explorer 8 seems to totally ignore the browser language settings. Even Google appears in English when I set my browser language to fr-FR in Internet Explorer 8. Only Google ignores the browser language settings for Internet Explorer 8. The Safari browser provides no means to change the browser language although you can change the application interface into French by copying the fr.lproj folder over the en.lproj folder. Opera does allow you to change the preferred language for web pages and you can change the user interface language to French by downloading the ouw960_fr.lng file which causes the user agent string to change to: Opera/9.63 (Windows NT 5.1; U; fr) Presto/2.1.1.

The browser language setting is communicated to the web server using the Accept-Language header in each request. In ASP.NET 2.0 you really don’t need to deal with this because the framework has built-in support for localization using the page directives UICulture and Culture. However, if you want to redirect to a page based on the browser language then you can use the following code in your Global.asax file:

   1: Sub Application_Start(ByVal sender As [Object], ByVal e As EventArgs)
   2:         Dim LanguageArray As String() = System.Web.HttpContext.Current.Request.UserLanguages
   3:         If LanguageArray(0).Contains("fr") Then
   4:             System.Web.HttpContext.Current.Response.Redirect("bonjour.htm")
   5:         End If
   6: End Sub

In PHP you can get the Accept-Language header using the server variable $_SERVER['HTTP_ACCEPT_LANGUAGE'];  and then set the locale using  setlocale(LC_ALL, 'fr-FR@euro', 'fr-FR', 'fr-fr');  which will automatically format the date using French for the month names and weekday names. You then need to set the Time Zone using putenv("TZ=Europe/Paris"); to get a 24 hour time in the Central European Time zone. On a Windows server the money_format function will not be available to you so you’ll need to define your own function for that.

But I’ve found a more interesting technological solution for the language barrier. I bought a Pocket PC translator from ECTACO. This device looks like a Pocket PC and it is Microsoft Windows Powered but it is really a highly specialized device with a built-in microphone and large speaker. I’m not sure what operating system it is running but it does not look like Windows Mobile 2003. I think its audio phrasebook may come in handy although it could make an awkward social situation even more awkward. The original SD card did not leave enough room for any additional audio files but I managed to copy everything over to a 2 GB SD card so I could put more MP3s on it.


Find more videos like this on VloggerHeads

I recently finished reading the book ASP.NET 3.5 Social Networking by Andrew Siemer. I was very interested in this book because I want to build a social networking site designed for vloggers and ASP.NET is my area of expertise. Currently I'm working to customize the Elgg social networking web application using PHP because it is open source and has an active developer community.

Unfortunately, developing a social networking application is a big project, not something the lone developer can accomplish. It really requires an integrated suite of web applications with modules for blogging, forums, groups, media galleries, etc. Andrew Siemer has done an impressive job of creating the framework of a social networking web application as documented in his book but it is by no means feature complete. There was no mention in the book of any plans to make this an open source project.

The author has clearly been keeping up with changes in technology and methodology. As far as ASP.NET 3.5 goes, he made extensive use of LINQ to SQL but was unable to use MVC which wasn't available at the time, although he managed to implement a MVP (Model View Presenter) design pattern. He also made use of open source tools like Lucene.NET, MemCached, StructureMap, and NUnit. I don't have any experience with those tools and I'm not up to speed with ASP.NET 3.5 but I considered this a bonus because I learned something new.

Even though I'm not using ASP.NET on my social networking project I still wanted to read this book to pick up on some tips on how to design such an application. Andrew Siemer provides plenty of explanation for his design decisions including how his database schema is structured according to the project requirements. This can eliminate one of the biggest stumbling blocks to a large project because a lot of time is wasted just figuring out how to design the database. Elgg is using the Entity Attribute Value model for its database and there is some debate over how well this will scale.

Although Andrew Siemer added considerable complexity to his project by using StructureMap, I guess this is wise because a social networking web application needs to be flexible. This design decision would definitely make sense for an open source project. StructureMap is a Dependency Injection tool written in C# for .NET development. StructureMap is also a generic "Plugin" mechanism for flexible and extensible .NET applications. In other words, it allows other developers to replace an object with some other implementation.

Social networking sites tend to get a lot of feature requests and suggestions from their large community of users. You really have to participate on several sites to get a sense of what the users are likely to need. Although the author anticipated many potential issues and requirements he did neglect to include some standard features. For example, he does not provide a means for members to customize their profile though CSS. Elgg also does not allow users to design their profile page and I know vloggers would miss this as they currently have a lot of fun creating new banners on Vloggerheads. I believe that vlogging is essential to create a really strong sense of online community so I found the media gallery component of the design particularly lacking. But you would need an entire video sharing module to really address that need. That is a huge project in its own right. I've learned that comment threading is really important for social networking sites. Without it you get users typing the @ sign in their comments to indicate who they are replying to and that is just an awkward user hack to work around a serious design flaw in the application.

Although this is a thick book, 556  pages, most of the content is code listings so you won't need to invest too much time in reading it. You may feel a little lost if you haven’t been following the rapid changes in the ASP.NET framework and the additional open source tools require additional work to familiarize yourself with them because they are not part of the ASP.NET framework.

Yesterday I attempted to create an ASP.NET page which used every single page event in order to better understand how to use each event. You cannot find any sample code for many page events. I managed to write code for every event except Page_AbortTransaction, Page_CommitTransaction, Page_DataBinding, and Page_Disposed which aren't being fired for this page. I tried to use meaningful examples but some of the code may be pointless. Let me know if you see any mistakes or have suggestions for improvements because this has gone into my notes.

The ASPX page includes a placeholder for adding a dynamic control and a GridView for experimenting with control rendering. I used the Northwind database for sample data. I also used a master page.

   1: <%@ Page Language="VB" MasterPageFile="~/Default.master" AutoEventWireup="false" CodeFile="LifeCycle.aspx.vb" Inherits="LifeCycle" title="ASP.NET 2.0 Life Cycle" %>
   2: <%@ MasterType VirtualPath="~/Default.master" %>
   3: <asp:Content ID="Content1" ContentPlaceHolderID="Main" Runat="Server">
   4:     <asp:PlaceHolder runat="server" id="LabelPlaceHolder" />
   5:     <br />
   6:     <asp:GridView ID="GridView1" runat="server" CellPadding="4" ForeColor="#333333" GridLines="None">
   7:         <RowStyle BackColor="#F7F6F3" ForeColor="#333333" />
   8:         <FooterStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
   9:         <PagerStyle BackColor="#284775" ForeColor="White" HorizontalAlign="Center" />
  10:         <SelectedRowStyle BackColor="#E2DED6" Font-Bold="True" ForeColor="#333333" />
  11:         <HeaderStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
  12:         <EditRowStyle BackColor="#999999" />
  13:         <AlternatingRowStyle BackColor="White" ForeColor="#284775" />
  14:     </asp:GridView>
  15: </asp:Content>

The VB code behind file uses a text file trace listener to log the page events as they are fired. That actually has to be set up in the web.config file. The Page_PreRenderComplete has some code commented out. This code adds the HTML rendered by the entire page to the log file but it causes an error about an extra form tag so I only left it in for debugging purposes. The only interesting things I'm doing is adjusting the column header text for the GridView and adding a top row. Some of the other page event code could use better examples.

   1: Imports System.Diagnostics
   2: Imports System.Data
   3: Imports System.Data.SqlClient
   4: Imports System.IO
   5:  
   6: Partial Class LifeCycle
   7:     Inherits System.Web.UI.Page
   8:  
   9:     Protected Sub Page_AbortTransaction(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.AbortTransaction
  10:         System.Diagnostics.Trace.WriteLine("Page_AbortTransaction " & Now())
  11:     End Sub
  12:  
  13:     Protected Sub Page_CommitTransaction(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.CommitTransaction
  14:         System.Diagnostics.Trace.WriteLine("Page_CommitTransaction " & Now())
  15:     End Sub
  16:  
  17:     Protected Sub Page_DataBinding(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.DataBinding
  18:         System.Diagnostics.Trace.WriteLine("Page_DataBinding " & Now())
  19:     End Sub
  20:  
  21:     Protected Sub Page_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Disposed
  22:         System.Diagnostics.Trace.WriteLine("Page_Disposed " & Now())
  23:     End Sub
  24:  
  25:     Protected Sub Page_Error(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Error
  26:         ' Use this event to log a page error
  27:         Dim objException As Exception = Server.GetLastError().GetBaseException()
  28:         System.Diagnostics.Trace.WriteLine(objException.ToString())
  29:         System.Diagnostics.Trace.WriteLine("Page_Error " & Now())
  30:     End Sub
  31:  
  32:     Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
  33:         ' Use this event to read or initialize control properties.
  34:         Dim ContentPlaceHolder1 As ContentPlaceHolder = CType(Master.FindControl("Main"), ContentPlaceHolder)
  35:         Dim LabelPlaceHolder As PlaceHolder = CType(ContentPlaceHolder1.FindControl("LabelPlaceHolder"), PlaceHolder)
  36:         Dim lblMessage As Label = CType(LabelPlaceHolder.FindControl("lblMessage"), Label)
  37:         lblMessage.ForeColor = Drawing.Color.Black
  38:         System.Diagnostics.Trace.WriteLine("Page_Init " & Now())
  39:     End Sub
  40:  
  41:     Protected Sub Page_InitComplete(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.InitComplete
  42:         ' Use this event for processing tasks that require all initialization be complete.
  43:         Dim ContentPlaceHolder1 As ContentPlaceHolder = CType(Master.FindControl("Main"), ContentPlaceHolder)
  44:         Dim LabelPlaceHolder As PlaceHolder = CType(ContentPlaceHolder1.FindControl("LabelPlaceHolder"), PlaceHolder)
  45:         Dim lblMessage As Label = CType(LabelPlaceHolder.FindControl("lblMessage"), Label)
  46:         lblMessage.ToolTip = "Tooltip added during InitComplete event."
  47:         ' Set a value in the viewstate
  48:         Me.ViewState("Author") = "Robert S. Robbins"
  49:         System.Diagnostics.Trace.WriteLine("Page_InitComplete " & Now())
  50:     End Sub
  51:  
  52:     Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
  53:         ' Use the OnLoad event method to set properties in controls and establish database connections.
  54:         Dim cn As New SqlConnection
  55:         Dim objSqlCommand As New SqlCommand
  56:         cn.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings("Northwind").ToString()
  57:         cn.Open()
  58:         objSqlCommand.Connection = cn
  59:         objSqlCommand.CommandText = "SELECT ProductID, ProductName, UnitPrice FROM Products ORDER BY ProductName"
  60:         Dim objDataSet As DataSet = New DataSet()
  61:         Dim objSqlDataAdapter As SqlDataAdapter = New SqlDataAdapter()
  62:         objSqlDataAdapter.SelectCommand = objSqlCommand
  63:         objSqlDataAdapter.Fill(objDataSet)
  64:         GridView1.DataSource = objDataSet
  65:         GridView1.DataBind()
  66:         cn.Close()
  67:         System.Diagnostics.Trace.WriteLine("Page_Load " & Now())
  68:     End Sub
  69:  
  70:     Protected Sub Page_LoadComplete(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.LoadComplete
  71:         ' Use this event for tasks that require that all other controls on the page be loaded.
  72:         ' Example: Get data from a GridView row after databinding has occurred.
  73:         System.Diagnostics.Trace.WriteLine(GridView1.Rows.Item(5).Cells(1).Text, "Row 6, Cell 2")
  74:         System.Diagnostics.Trace.WriteLine("Page_LoadComplete " & Now())
  75:     End Sub
  76:  
  77:     Protected Sub Page_PreInit(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreInit
  78:         ' Check the IsPostBack property to determine whether this is the first time the page is being processed.
  79:         If Page.IsPostBack = False Then
  80:             ' Create or re-create dynamic controls.
  81:             Dim lblMessage As New Label
  82:             lblMessage.ID = "lblMessage"
  83:             lblMessage.Width = 500
  84:             lblMessage.Text = "Dynamically created control."
  85:             Dim ContentPlaceHolder1 As ContentPlaceHolder = CType(Master.FindControl("Main"), ContentPlaceHolder)
  86:             Dim LabelPlaceHolder As PlaceHolder = CType(ContentPlaceHolder1.FindControl("LabelPlaceHolder"), PlaceHolder)
  87:             LabelPlaceHolder.Controls.Add(lblMessage)
  88:         End If
  89:         System.Diagnostics.Trace.WriteLine("Page_PreInit " & Now())
  90:     End Sub
  91:  
  92:     Protected Sub Page_PreLoad(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreLoad
  93:         ' Use this event if you need to perform processing on your page or control before the Load event.
  94:         ' Viewstate should be available now because it has been loaded.
  95:         System.Diagnostics.Trace.WriteLine(Me.ViewState.Values.Count, "ViewState Count")
  96:         ' The Request object should be available now. 
  97:         System.Diagnostics.Trace.WriteLine(Request.ServerVariables("SCRIPT_NAME"), "Script Name")
  98:         System.Diagnostics.Trace.WriteLine("Page_PreLoad " & Now())
  99:     End Sub
 100:  
 101:     Protected Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRender
 102:         ' Use the event to make final changes to the contents of the page or its controls.
 103:         Dim ContentPlaceHolder1 As ContentPlaceHolder = CType(Master.FindControl("Main"), ContentPlaceHolder)
 104:         Dim GridView1 As GridView = CType(ContentPlaceHolder1.FindControl("GridView1"), GridView)
 105:         Dim objGridViewRow As GridViewRow
 106:         objGridViewRow = New GridViewRow(-1, -1, DataControlRowType.Header, DataControlRowState.Normal)
 107:         Dim objTableCell As TableCell = New TableCell()
 108:         Dim literal As LiteralControl = New LiteralControl()
 109:         literal.Text = "Northwind Products"
 110:         objTableCell.Controls.Add(literal)
 111:         objTableCell.ColumnSpan = 3
 112:         objTableCell.HorizontalAlign = HorizontalAlign.Center
 113:         objTableCell.ForeColor = Drawing.Color.White
 114:         objTableCell.BackColor = Drawing.Color.Black
 115:         objGridViewRow.Cells.Add(objTableCell)
 116:         GridView1.Controls(0).Controls.AddAt(0, objGridViewRow)
 117:         System.Diagnostics.Trace.WriteLine("Page_PreRender " & Now())
 118:     End Sub
 119:  
 120:     Protected Sub Page_PreRenderComplete(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRenderComplete
 121:         ' At this stage of the page life cycle, all controls are created, any pagination required is completed, and the page is ready to render to the output.
 122:         ' Example: The column headings of the gridview should be accessible now.
 123:         Dim ContentPlaceHolder1 As ContentPlaceHolder = CType(Master.FindControl("Main"), ContentPlaceHolder)
 124:         Dim GridView1 As GridView = CType(ContentPlaceHolder1.FindControl("GridView1"), GridView)
 125:         GridView1.HeaderRow.Cells(0).Text = "Product ID"
 126:         GridView1.HeaderRow.Cells(1).Text = "Product Name"
 127:         GridView1.HeaderRow.Cells(2).Text = "Unit Price"
 128:         ' Get the rendered HTML
 129:         'Dim objStringBuilder As New StringBuilder()
 130:         'Dim objStringWriter As New StringWriter(objStringBuilder)
 131:         'Dim objHtmlTextWriter As New HtmlTextWriter(objStringWriter)
 132:         'Me.RenderControl(objHtmlTextWriter)
 133:         'Dim strGridViewHTML As String = objStringBuilder.ToString()
 134:         'System.Diagnostics.Trace.WriteLine(strGridViewHTML)
 135:         System.Diagnostics.Trace.WriteLine("Page_PreRenderComplete " & Now())
 136:     End Sub
 137:  
 138:     Protected Sub Page_SaveStateComplete(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.SaveStateComplete
 139:         ' Use this event perform tasks that require view state to be saved, but that do not make any changes to controls.
 140:         ' Example: Lets store some extraneous information in the view state
 141:         Me.ViewState("Date") = Now()
 142:         System.Diagnostics.Trace.WriteLine("Page_SaveStateComplete " & Now())
 143:     End Sub
 144:  
 145:     Protected Sub Page_Unload(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Unload
 146:         ' Use this event to do final cleanup work, such as closing open files and database connections, or finishing up logging or other request-specific tasks.
 147:         System.Diagnostics.Trace.WriteLine(Me.ViewState.Values.Count, "ViewState Count")
 148:         System.Diagnostics.Trace.WriteLine("Page_Unload " & Now())
 149:     End Sub
 150: End Class

 

A SSIS (SQL Server Integration Services) package is very useful if you want to export data from your database. Recently I wanted to pass some input parameters to my SSIS package and had to struggle to figure out how this can be done. This really isn't very well documented and you can't find detailed instructions on the Internet so I thought I'd blog about it. Get a load of how complicated it turned out to be!

The first step is to add a variable to your SSIS package. In the Business Intelligence Development Studio (Visual Studio 2005), select SSIS > Variables

SSIS-Variables

The first button on the left is for Add Variable. Enter the variable name, scope, data type, and value. The variables will be added to the DTSX file:

   1: <DTS:Variable>
   2:     <DTS:Property DTS:Name="Expression"></DTS:Property>
   3:     <DTS:Property DTS:Name="EvaluateAsExpression">0</DTS:Property>
   4:     <DTS:Property DTS:Name="Namespace">User</DTS:Property>
   5:     <DTS:Property DTS:Name="ReadOnly">0</DTS:Property>
   6:     <DTS:Property DTS:Name="RaiseChangedEvent">0</DTS:Property>
   7:     <DTS:VariableValue DTS:DataType="7">1/1/1950</DTS:VariableValue>
   8:     <DTS:Property DTS:Name="ObjectName">varBirthDate</DTS:Property>
   9:     <DTS:Property DTS:Name="DTSID">{6CE1ED2D-3720-4FDB-9590-FEDC2D78C797}</DTS:Property>
  10:     <DTS:Property DTS:Name="Description"></DTS:Property><DTS:Property DTS:Name="CreationName"></DTS:Property>
  11: </DTS:Variable>

The next step is to map a parameter in your SQL statement to the variable.

  1. Select the Data Flow tab.
  2. Right click on the Source Query
  3. Select Edit
  4. Replace a hard coded value in the SQL statement with a question mark to create a parameter
  5. Click the Parameters... button
  6. Select the variable from the drop down list
  7. Enter the parameter name in the format @Name for a stored procedure parameter or the field name

SSIS-OLE-DB-Source-Editor

SSIS-Set-Query-Parameters

The third step is to add this variable to the package configuration so you can easily change the value in an XML configuration file.

  1. Select SSIS > Package Configurations
  2. Click the Edit button and then the Next button
  3. In the Select Properties to Export dialog box, check the Value property of the variable (which will not appear unless you complete the previous steps to create it first).

SSIS-Package-Configuration-Wizard

The variables will be added to the .dtsConfig file:

   1: <Configuration ConfiguredType="Property" Path="\Package.Variables[User::varBirthDate].Properties[Value]" ValueType="DateTime">
   2:         <ConfiguredValue>1/1/1950</ConfiguredValue>
   3: </Configuration>

The SSIS package can be run by an ASP.NET page or a web service by importing the Microsoft.SqlServer.Dts.Runtime namespace. The input parameter can easily by changed in the package configuration file by loading it as an XML document and editing the appropriate node.

You can use SSIS packages to do very complicated data transformations and exports. Basically it automates everything the SQL Server Import and Export Wizard does. So you can export your database to Access or Excel without repeating that whole process of going through the wizard steps. I've found this particularly useful to set up my own scheduled back up of a remote SQL Server database used by a hosted web application.

I recently read a new book published by Packt Publishing, “ASP.NET 3.5 Application Architecture and Design” by Vivek Thakur. I've noticed a lot of articles and blog posts about design patterns and domain models in the ASP.NET community but it really mystified me until I read this book. Although many of the blog posts I've read have tried to be an introduction to design patterns, I'd have to say they all did a poor job compared to Vivek Thakur's book which explains it all in plain English. I learned how application architecture applies to web development and what advantages it is meant to offer.

For example, the chapter on tiers and layers explains how the business layer, UI layer, and data access layer relates to namespaces and classes you could create to organize your project. The chapter on entity-relationships clarified how the domain model used in the object-oriented system may differ from the logical data model used in the relational database management system.

I also found good explanations of; lazy loading, to defer the loading of all properties until they are really needed, the singleton pattern, which restricts and controls the number of objects instantiated for a particular object during the application life cycle,  the factory method, used to create objects without prior knowledge of the object using interfaces, and dependency injection, which allows you to plug-in an implementation that satisfies the interface requirements. Although I've come across these terms before I had no idea what they meant or how they could apply to ASP.NET. You'll find some really basic examples of how you can write code to use these design patterns.

If you are an expert on application architecture and expect in-depth coverage of how to apply the factory method in ASP.NET then you'll be disappointed. I'd say this book is more helpful for someone like me, a developer who is completely mystified by what everyone seems to be writing about these days. That is not to say you might not pick up a few tips from the material. For example, page 137 mentions a lock statement that can be used to ensure thread safety and I'd never encountered that before.

I also appreciated the author's practical approach to design patterns. He does not recommend them for small projects. This kind of lets me off the hook because none of my projects could really justify the additional overhead of a loosely-coupled design. However that is not to say you won't encounter such design patterns in your work. For example, I'm currently trying to customize the Elgg open source web application for social networking and its database schema is a peculiar attempt to incorporate entity relationships directly in the physical data layer. In any event, you are not meant to directly access the database. Instead you should get a reference to an ElggObject and use its properties. 

I have not been blogging here because I've been doing a lot of web design research lately which does not involve ASP.NET. I'm really slacking off on improving my programming skills. I went on a fabulous vacation and never came back mentally. However I'm still making the effort to master web design so I will share some of my recent discoveries.

Yesterday I learned about the "computed style" in CSS. I don't know why I've never come across this term before now. There are so many little details in web development. I'm always finding holes in my knowledge. Any way, a computed style is the value a CSS property will have when the browser needs to calculate the value based on a percentage or a value relative to another value. For example, if you specify a div to have a width of 50% and it contains an element that inherits its width from the div, then that element will have a computed value.

I had to figure this out because I'm using the http://www.plaintxt.org/themes/sandbox/ WordPress theme as a template for a custom theme. The web design community seems to be very keen on WordPress. You can find many tutorials on how to design for WordPress. I was working on the header for my design and found it would not appear at the top of the page in Firefox. There was a gap between the top of the page and my header. I examined the layout in Firebug and saw a 16 pixel offset on the top of the header element:

I could not figure out where that 16 offset was coming from. There was nothing in my CSS to set any height to 16px. Eventually I tried the developer tools in other browsers. Opera told me that there was a top: 16px computed style for my header element. So I had to learn about computed styles and how to deal with them.

The height for a block-level element is calculated in CSS. If such an element has no height defined, it will be set to auto, which is the default height for block-level elements. You have to change the height of the div by either adding a border or a padding to avoid the computed style.

So to eliminate that computed value I had to add a little padding to the top. As you can see I did have its height defined so I don't know why there was still a problem.

   1: #header {
   2:     background: #FFFFFF url(images/header_img.jpg);
   3:     height: 145px; /* height of image */
   4:     padding-top: 1px;
   5: }
The following CSS property values will result in a computed value; ‘auto’, ‘inherit’, ‘50%’, ’smaller’, ‘1.5em’ etc.

The web site I've been working on, Vloggerheads, will be opened to the public tomorrow. You can view the videos and blogs but you won't be able to comment or post videos unless you request membership and are approved. You might want to check out the video of the shrine that was built to me or the many videos thanking me for adding much needed features to the site. LOL

Vloggers make so many videos that it is not unusual for them to make a video about the site itself. I get a lot more feedback and appreciation for my work on this web site than I get on any other project. This alone makes it very worthwhile. If you are looking for recognition from users than you should definitely consider a video sharing site project.

I've added several features to this Ning site which everyone was used to having on YouTube or LiveVideo. Leaving comments on videos is an important aspect of the communication in the community so I added comment threading and comment replies. I also implemented email notification for comment replies. Working with the Ning platform is painfully difficult. Just sending an email proved to be a major hassle because Ning does not give me direct access to a member's email address. I have to use their built-in classes to send emails. And I cannot query for more than 100 content items at a time so I need to write a loop to get all the comments. Ning fights me every step of the way and frustrates me with its caching system and poor error reporting tools.

Ning is dropping the old version of the Dojo JavaScript library they were using and replacing it with jQuery. So I'm glad that ASP.NET will officially support jQuery as I'll be using it on all my projects. I've already included jQuery in my two remaining ASP.NET projects and I imported it into my Ning sites. I even use jQuery in my help files that I use for documentation.

I wrote some very complicated JavaScript to handle the comment pagination so I've been using every tool available to me to troubleshoot my JavaScript. Since the Ning platform caches JavaScript on the server side I've found it useful to load my recently changed scripts in Firebug to double check the version downloaded by Firefox. I've even resorted to using some console.log("string") lines in my code to avoid annoying alerts. My JavaScript is loading and manipulating XML so I've had to view my JavaScript objects in the DOM pane to carefully review available properties and methods. However, I haven't neglected the new debugging tools in Internet Explorer 8.0 Beta. I even have to use Opera to get an error message for a Dojo library error that won't show up in Firefox or Internet Explorer. I was uncertain as to what values the Ning platform was expecting for a POST request so I learned how to use Firebug to view what was being sent in a typical POST request.

During a recent Skype conference I was surprised to learn that both YouTube and LiveVideo were more disinterested in the vlogging community than I suspected. This surprises me because I think the social networking potential of vlogging is obvious. Vlogging is clearly more effective than blogging and other forms of text in fostering a genuine sense of online community. You can form real friendships through vlogging that would never take place among bloggers. Unfortunately, too many Web 2.0 entrepreneurs focus on valuations and numbers and neglect to consider the most important factor of business value, providing a service that meets real needs. You can never go wrong betting on a business that meets the needs of the general public. Vlogging clearly meets many crucial needs. It provides social interaction for the socially isolated. It provides recognition for creative people. It provides entertainment and communication that is more interactive than the mass media can offer. To dismiss vlogging as something that will never catch on with the general public is as stupid as it was two years ago to dismiss blogging as a fad.

More Posts Next page »