Navigation


RSS: Matt Pavey RSS Feed



Sunday, September 16, 2007 @ 9:28 am,VB.Net,Matt Pavey

On several occassions I work with XML data and sometimes binding it to one of the standard ASP.Net controls doesn't quite give you the flexibility necessary to display the data how you need to, especially when dealing with hierarchical data more than a couple of levels deep.

You could always load the XML data and parse through it and build your controls manually; however, sometimes that is hard to do for very complex hierarchies.

In some cases a better solution is XSL.

XSL is a family of recommendations for defining XML document transformation and presentation.

XSL Transformations (XSLT)
A language for transforming XML

XML Path Language (XPath)
An expression language used by XSLT to access or refer to parts of an XML document. (XPath is also used by the XML Linking specification)

XSL Formatting Objects (XSL-FO)
An XML vocabulary for specifying formatting semantics

If you don't use XSL or know much about it and are wanting to learn I highly recommend Michael Kay's XSLT 2nd Edition Programmer's Reference by WROX Books. In my opinion Michael is one of the leading experts on the subject and you'll consistently see him posting on online forums about what XSL is and the proper way to use it, etc.

Over the course of several years I've used XSL in a number of ways such as re-transforming XML data from one format to another, advanced sorting capabilities, or displaying hierarchical data in a very specific format. The powerful capabilities of this language are too large in number to begin to outline or describe in this article; however, one thing that I would like to mention is how you can actually implement an XSL transformation in your code very easily, and in a generic fashion that can be utilized throughout your projects with minimal effort.
 
You'll find the Xsl class and Functions class that I use in several of my projects at the following links:
 
 
 
The purpose of this class is to centralize many of the things I have come across while using XSL and have them easily accessible and configurable in a reusable class.
 
This class will let you transform XML data in a file or XML data passed in directly as a string. It could easily be modified to accept the XML as an XMLDocument or other format if needed.
 
Another interesting thing I want to point out is that the TransformXml function is overloaded to accept either the path of the XSL file or a custom XSL configuration object (XslConfiguration).
 
Sometimes your code might need to be as simple as passing in XML data and an XSL path and getting back the results:
 
Using Xsl As New Utilities.Xsl()
    
News.Text = Xsl.TransformXml(Utilities.Xsl.XmlTypes.XmlData, XmlData, Server.MapPath("~/Test.xsl"))
End Using
 
However sometimes you have more complicated requirements, thus the overloaded version of the TransformXml function can take an XslConfiguration object as a parameter. This allows you to define a number of other things besides the XSL path, including parameters that the XSL transformation needs and an ExtensionObject if you need to execute custom functions from within the transformation.
 
Here's a similar example using the XslConfiguration object and only specifying an XSL file, no advanced configuration settings:

Using Xsl As New Utilities.Xsl()
    
Using XslConfig As New Utilities.Xsl.XslConfiguration(Server.MapPath("~/Test.xsl"))
         
HtmlData = Xsl.TransformXml(Utilities.Xsl.XmlTypes.XmlData, XmlData, XslConfig)
    
End Using
End Using

And here's another example using the XslConfiguration object with some of the more advanced settings:

Using Xsl As New Utilities.Xsl()
    
Using XslConfig As New Utilities.Xsl.XslConfiguration()
         
'xsl file path
         
XslConfig.XslFile = XslFile

         
'extension object with a function that will be accessible in our transformation
         
XslConfig.ExtensionNameSpace = "urn:ext"
         
XslConfig.ExtensionObject = New ExtensionObject

         
'parameters required in the xsl transformation
         
XslConfig.SetXslParameterNames("Parameter1Name", "Parameter2Name")
         
XslConfig.SetXslParameterValues("Parameter1Value", "Parameter2Value")

         
'transform the data
         
HtmlData = Xsl.TransformXml(Utilities.Xsl.XmlTypes.XmlData, XmlData, XslConfig)

         
'check for errors
         
If Xsl.ErrorDescription <> String.Empty Then
              
HtmlData = xsl.ErrorDescription
         
End If
    
End Using
End Using
 
Of course for the previous code to work you to define the ExtensionObject class or whatever you chose to name your class, for example:

Private Class ExtensionObject
    
Public Function IsImageAvailable(ByVal Image As String) As String
         
Return File.Exists(HttpContext.Current.Server.MapPath("~/Images/" & Image))
    
End Function
End Class
 
The actual XSL transformation code could look something like:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ext="urn:ext" version="1.0">
    
<
xsl:output media-type="html" omit-xml-declaration="yes"/>

    
<
xsl:param name="Parameter1Name" />
    
<
xsl:param name="Parameter2Name" />

    
<
xsl:template match="/">
         
Parameter1Name: <xsl:value-of select="$Parameter1Name"/><br/>
         
Parameter2Name: <xsl:value-of select="$Parameter2Name"/><br/>

         
<
xsl:apply-templates select="//Row">
              
<
xsl:sort select="LastName" data-type="text" order="ascending" />
              
<
xsl:sort select="FirstName" data-type="text" order="ascending" />
         
</
xsl:apply-templates>
     </
xsl:template>
 
     <xsl:template match="Row">
         
<
xsl:variable name="ShowImage" select="ext:IsImageAvailable(Image)"/>
         
         
<
xsl:choose>
              
<
xsl:when test="$ShowImage='True'">
                   
<
img src="Images/{Image}" />
              
</
xsl:when>
              
<
xsl:otherwise>
                   
<
img src="Images/ImageNotAvailable.jpg" />
              
</
xsl:otherwise>
         
</
xsl:choose>
    
</
xsl:template>
</
xsl:stylesheet>
 
Notice how we have our xmlns:ext attribute declared in the xsl:stylesheet node. That is what ties our extension namespace back to what we specified in the code-behind:

XslConfig.ExtensionNameSpace = "urn:ext"

And we've defined our 2 parameters that we passed in.
 
It also demonstrates how we can call our custom function from our extension object, like so:
 
<xsl:variable name="ShowImage" select="ext:IsImageAvailable(Image)"/>
 
That's all there is to having a custom XSL class that can be reused for a lot of different scenarios!


Sunday, September 16, 2007 @ 8:02 am,VB.Net,Matt Pavey

Here's a simple class that I use regularly to configure and send e-mail messages using the System.Net.Mail assembly.
 
You'll find the Email class and Functions class that I use in several of my projects at the following links:
 
 

An example of using this code might look something like this:

Using xmail As New Utilities.Email()
     xmail.SMTPServer = Configuration.Email.SMTP_Server
    
xmail.SMTPServerPort = Configuration.Email.SMTP_ServerPort
    
xmail.SMTPConnectionTimeOut = Configuration.Email.SMTP_ConnectionTimeOut
    
xmail.SMTPDeliveryMethod = Configuration.Email.SMTP_DeliveryMethod
    
xmail.SMTPUseSSL = Configuration.Email.SMTP_UseSSL
    
xmail.SMTPUserName = Configuration.Email.SMTP_UserName
    
xmail.SMTPPassword = Configuration.Email.SMTP_Password

    
xmail.AddSender(FromAddress, FromName)

    
For Each EmailAddress As String In ToAddress.Split(";")
         
If EmailAddress.Trim.ToString <> String.Empty Then
              
xmail.AddRecipient(EmailAddress)
         
End If
    
Next

    
xmail.Subject = Subject
    
xmail.IsBodyHtml = True
    
xmail.Body = EmailBody
    
xmail.Send()
End Using

Because our Email class Implements IDisposable we are able to use the shorthand Using/End Using block.


Friday, September 14, 2007 @ 6:09 pm,VB.Net,Matt Pavey

Here's another example of how to use generics to retrieve data and return it as the data-type you want to work with.
 
Public Function GetValueFromIDR(Of ItemType)(ByVal IDR As IDataReader, ByVal FieldName As String) As ItemType
     Dim ReturnData As ItemType
 
     If IDR(FieldName) IsNot Nothing Then
         
If Not IsDBNull(IDR(FieldName))
Then
              
ReturnData = IDR(FieldName)
          End
If
    
End
If

    
Return ReturnData
End Function
 
And here's an example of calling it:
 
Dim EventName As String = GetValueFromIDR(Of String)(IDR, "EventName")
 
The use of generics can simplify your code and avoid having to always cast values from one data-type to another.


Friday, September 14, 2007 @ 5:48 pm,VB.Net,Matt Pavey

Using multiple master pages is becoming more handy lately. When I first started using master pages I typically had 1 or 2 of them in a project and a page would only make sense to be viewable in one of those master pages. A good example is having a "public" master page and an "admin" master page.
 
But on one of my projects there is a wide variety of master pages available to provide several different "experiences" based on what the user is trying to do or what the user is viewing.
 
There is one particular scenario where I wanted to let the user see the content in a different master page (e.g. normal view vs. print view) and I wanted to control it based on a querystring parameter, so I needed to change the master page at runtime.
 
Changing the master page programatically in your code-behind file is easy to do, it's just important to know that you have to do it early enough in the page's life-cycle for it to actually work.
 
You can change the master page in the PreInit event.
 
Private Sub Page_PreInit(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreInit
     MasterPageFile = "~/Template2.master"

End Sub
 
The PreInit event is new to ASP.Net 2.0. If you try to wait to change the master page in the page's Load or Init event it will be too late!
 
When changing the master page dynamically, you must make sure that all master pages have the same ID for the ContentPlaceHolder controls, so that the content page's Content controls will always match them, regardless of which master page is being used.


Friday, September 14, 2007 @ 5:40 pm,VB.Net,Matt Pavey

Here's an easy way to provide some nifty "highlight" effects to a web form to give the user a helpful visual experience.
 
I think most of us already know the concept of a BasePage and what they are used for, and in general they more times than not are helpful to use as they can provide some very basic functionality to a variety of pages with very little effort. So without getting in to setting up the base page too much, just know that you can create a BasePage in C# or VB and have it inherit from System.Web.UI.Page. In one particular case I have multiple base pages for a variety of things done throughout the site, but the base of all base pages is typically my BasePage.vb file.
 
In BasePage.vb I override the OnLoad page event which looks like:
 
Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
    
'add onfocus and onblur to controls so active control has a different appearance
     Utilities.Helpers.SetInputControlsHighlight(Page, "highlight", True)
    
MyBase.OnLoad(e)
End Sub
 
In my case I call a SetInputControlsHighlight function that I have in another class in my "Utilities" project, although technically you could have the function directly in the base page if you desired. The function is as follows:
 
Public Shared Sub SetInputControlsHighlight(ByVal container As Control, ByVal ClassName As String, ByVal OnlyTextBoxes As Boolean)
     For Each ctl As Control In container.Controls
          If ((OnlyTextBoxes AndAlso TypeOf ctl Is TextBox)
              Or (Not OnlyTextBoxes
                   AndAlso (TypeOf ctl Is TextBox
                   Or TypeOf ctl Is DropDownList
                   Or TypeOf ctl Is ListBox
                   Or TypeOf ctl Is CheckBox
                   Or TypeOf ctl Is RadioButton
                   Or TypeOf ctl Is RadioButtonList
                   Or TypeOf ctl Is CheckBoxList)))
Then
              
Dim wctl As WebControl = CType(ctl, WebControl)
               wctl.Attributes.Add("onfocus", String.Format("this.className = '{0}';", ClassName))

               wctl.Attributes.Add("onblur", "this.className = '';")
         
Else
              
If (ctl.Controls.Count > 0)
Then
                   
SetInputControlsHighlight(ctl, ClassName, OnlyTextBoxes)
               End
If
         
End
If
    
Next
End Sub

The function is pretty simple. It's setup to take the root container as a parameter and it will apply the specified class (e.g. "highlight") to the controls in that container. There is also a parameter to specify if you want the style applyed to all input controls on the form or specifically just TextBox controls.

In my case when the user clicks on an input control on the form it shows the control with a different color so it's obvious that it has the focus, then when the focus is lost it goes back to normal, etc. It can easily be modified to apply to other situations.

The original idea for this code was based the book ASP.NET 2.0 Website Programming: Problem - Design - Solution by Marco Bellinaso. It's one of the best books I've used throughout my career. It's published by WROX, and all of their books are usually very good (in my opinion), but this one is different than most because rather than a typical reference book, it's actually a step by step solution for building an ASP.Net 2.0 website from the ground up, from listing requirements, identifying problems, designing the database, architecting the solution, implementation, all the way to deployment, etc.


Friday, September 14, 2007 @ 11:20 am,VB.Net,Matt Pavey

This makes life much easier when you're trying to get to controls that are themselves contained within other containers, eg, a TextBox inside a DataView or DataList.

Public Function FindControlRecursive(Of ItemType)(ByVal Ctrl As Object, ByVal id As String) As ItemType
    
If String.Compare(Ctrl.ID, id, StringComparison.OrdinalIgnoreCase) = 0 AndAlso TypeOf Ctrl Is ItemType Then
          Return
CType(Ctrl, ItemType)
     End If
 
     For Each c As Control In Ctrl.Controls
         
Dim t As ItemType = FindControlRecursive(Of ItemType)(c, id)

         
If t IsNot Nothing Then
               Return
t
         
End If
     Next
 
     Return Nothing
End
Function

This example also demonstrates the use of Generics, which before .Net 2.0 was only available with cast typing and use of base objects, etc. There are several good articles online about generics, but here are a couple to get you started.


Saturday, July 28, 2007 @ 7:29 pm,VB.Net,Matt Pavey

Excerpts from an article written by Dan Mabbutt entitled VB .NET New Logical Operators.

VB .NET features two new logical operators that help make your programming ... well ... more logical. The new operators are AndAlso and OrElse and they generally replace the VB 6 operators And and Or (but they do much more!).

The old VB 6 And and Or are still present in VB .NET. If you decide that they're what you need your program, go ahead and use them. They work the same way they used to work.

But AndAlso and OrElse have some properties that enhance your code in ways that VB 6 can't match. They offer advantages in two general categories:

  • You can avoid executing part of a logical expression to avoid problems.
  • You can optimize code by not executing any more of a compound expression than required.
AndAlso and OrElse are pretty much like And and Or except that they will "short circuit" an expression once the outcome is guaranteed.

Knowing about these two new VB .NET logical operators can help you avoid very subtle errors or achieve subtle efficiencies.


Thursday, April 12, 2007 @ 3:11 pm,VB.Net,Matt Pavey

Remember the "Using" block is a convenient, shorthand notation for the Try-Finally block. "Using" and "End Using" ensures that Dispose is called even when an exception occurs - and that's a good thing.


The opinions expressed on this website are my personal opinions
and do not represent my employer's or my clients' views in any way.