in

Fort Worth .NET Users Group

David.Yancey

  • Throw Away Code (aka Spike Solution)

      I’ve been talking with a few of my programmers the past few days about the concept of throw away code, asking them if they’ve heard of the concept, or if they’ve thought about implementing it on their teams.   All but one of them replied back to me with variations of “what a waste of time”, [...]
  • Code Noise Part 2!

    Last time we looked at what Code Noise was.  This time we are going to look at good practices for eliminating code noise. Clean Naming: Clean names reveal intent. Clean names reveal intent. Clean names reveal intent. The point I’m trying to get across here is that good clean names reveal intent.  So what do I mean by this?  Names [...]
  • Temporary Post Used For Style Detection (20612a80-808c-491a-a391-9e369da44799 - 3bfe001a-32de-4114-a6b4-4005b770f6d7)

    This is a temporary post that was not deleted. Please delete this manually. (3adf98b1-023e-4314-82ae-42e8b693567a - 3bfe001a-32de-4114-a6b4-4005b770f6d7)
  • Dirty Code!!!

    If 4 letter words immediately come to mind when you do a code review…then you might have dirty code. If you quince each time a new feature is requested to be added to your existing library of code…then you might have dirty code. If the amount of time it takes to research a bug is inversely proportional [...]
  • Code Noise!!!

    If 4 letter words immediately come to mind when you do a code review…then you might have dirty code. If you wince each time a new feature is requested to be added to your existing library of code…then you might have dirty code. If the amount of time it takes to research a bug is inversely proportional to [...]
  • Refactoring: Getting started is the hard part

    Just the thought of ‘refactoring’ can be daunting to a programmer.  Martin Fowler defines ‘refactoring’ as: Refactoring is a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior. Its heart is a series of small behavior preserving transformations. Each transformation (called a ‘refactoring’) does little, but a sequence [...]
  • Agile and the .NET Community

    Why does it seem that the .NET Community isn’t very active in the Agile community?  I know that there are Agile practitioners in various .NET shops however, it seems that the overall representation is very minimal.  Is it because of a lack of understanding of the Agile methodologies? Or is there a lack of support [...]
  • Taking a look at Dynamic Data

    One of the best things about being a programmer is new technologies,  taking a look at exciting new approaches to everyday tasks.  The .NET world is continually growing, in fact it was only 6-months ago that the 3.5 Framework was released giving you new tools such as LINQ, WPF, and Silverlight.  Now comes ASP.NET 3.5 Extensions Preview and you can add to the list Dynamic Data Controls. Dynamic Data Controls will enable you to build data driven website's that will work against a LINQ to SQL and LINQ to Entities object model.  With a fully functional website built on top of the MVC framework you can optionally override or customize any of the view templates giving you full control over our website.

    Dynamic data works with the standard data controls enabling them to automatically support foreign key relationships,  giving you a friendly name display of foreign key values along with built in UI validation support based upon the constraints set in your data-model.

    Once you download the new Dynamic Data controls (you can down load them from here ) unzip them to your favorite directory.  Inside the directory you will find a series of DLL's, Zip files, CMD files and a readme.  Inside the readme you will find instructions on setting up your environment and your first project of which both of these we will go over in this blog.  So now its time to get to the fun.

    image

    For this example you will need

    Visual Studio 2008
    SQL Express
    ASP.NET 3.5 Extensions Preview
    Northwind database

    The examples here will be in VB.NET, however you can use C# if you so desire.

    Installation

    First you need to install the Dynamic Data controls.  To do this you can either open up a command window and navigate to the directory in which you unzipped the files, or you can simply double click on the appropriate one to install depending upon your system.  You will notice that there is support for both 32-bit and 64-bit operating systems.

    Your first Project

    Launch Visual Studio 2008, and click on File > New > Website and choose Dynamic Data Website (Preview).

    imageA

     

    Directory Structure:
    You will notice that you have a pre-built website complete with a Dynamic Data directory structure.  The key area's I want to point out here are the CustomPages, FieldTemplates, and PageTemplates directories. 

    imageB

     

    FieldTemplates:These are the templates which are used to render each of the field types with in your datamodel.  You will notice the standard data types such as Boolean, DateTime, Integer, and Text.  You should also notice templates to handle the rendering of ForeignKey and Children relationships.  What you should also notice is that the templates for Image and XML data types are missing.  As of this release they are not installed by default; however you can create your own templates to control the rendering of these datatypes.  You can also override/customize the existing templates depending upon your needs.

    PageTemplates:These are the default page templates to display / edit the data. 

    CustomPages:This is where you will put any custom pages or override any pages in the default PageTemplates directory.

     

     

     

    Data Model:

    Add your database to your project.

    Add a LINQ to SQL Class

    imageC

    Add the desired tables to your datacontext.

    imageD

    Now its time for the magic.  Open your global.asax and uncomment the line:

    '    model.RegisterContext(GetType(YourDatacontext), New ContextConfiguration() With {.ScaffoldAllTables = False})

    Then replace "YourDatacontext" with the name of the datacontext we just created and set ScaffoldAllTables = True.  Setting this value will build the dynamic pages based upon the data model.

       1: <%@ Application Language="VB" %>
       2: <%@ Import Namespace="System.Web.Routing" %>
       3: <%@ Import Namespace="System.Web.DynamicData" %>
       4:  
       5: <script RunAt="server">
       6: Public Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
       7:     Dim model As New MetaModel
       8:  
       9:     ' Uncomment this line to register your data context with the Dynamic Data engine.
      10:     ' Only set ScaffoldAllTables = true if you are sure that you want all your tables
      11:     ' to support a scaffold (i.e. templated) view.
      12:         model.RegisterContext(GetType(NorthwindDataContext), New ContextConfiguration() With {.ScaffoldAllTables = True})
      13:  
      14:     routes.Add(New DynamicDataRoute("{table}/ListDetails.aspx") With { _
      15:         .Action = PageAction.List, _
      16:         .ViewName = "ListDetails", _
      17:         .Model = model})
      18:  
      19:     routes.Add(New DynamicDataRoute("{table}/ListDetails.aspx") With { _
      20:         .Action = PageAction.Details, _
      21:         .ViewName = "ListDetails", _
      22:         .Model = model})
      23:  
      24:     'routes.Add(New DynamicDataRoute("{table}/{action}.aspx") With { _
      25:     '    .Constraints = New RouteValueDictionary(New With {.Action = "List|Details|Edit|Insert"}),
      26:     '    .Model = model})
      27: End Sub

     

    Now run the site.

    imageE

    Drilling down to the Product details you will see that the friendly names for the categories are in both the drop down list, and the grid view.  You will also notice the ability to edit and delete.

    So now go off and have some fun with this.  Next time we will look at adding support for the Image data type based upon Scott Hunter's sample and building our own custom pages.

    So until next time, have fun and I'll see ya on the flip side.

    David Yancey

  • Using Provider Model with Unit Testing

    We are going to look at the Provider model and Offloader/Worker model and how we use this approach for our Test Driven Development (TDD) and Unit Testing.  For this Demo we will be using the Northwind Database, and developing this in VB. To start off we need to set up 3 projects in the same solution:

    1. TCNorthwindClass:  This is were we will place our class files for the BLL, DAL, and Interface.
    2. TCNorthwindWeb:  For this demo we will be creating a webservice.
    3. TCNorthwindTest:  For our Unit Tests.

    Now lets look at what the provider model is and how we use it with in our application.

    Provider Model

    We are going to define the provider model as a model in which the provider (access to the DAL) is passed in as an argument to the worker methods.  When developing your application using the provider model, you are going to create first your Interface with which all provider classes will implement.Diag1  

    Looking at the diagram to the left you will see that we have our Interface along with 2 class files of which one we are defining as a mock.  We'll look more at this later.  What's important to see here is that in our provider class files we are defining what is to be done with the data.  Each class implements from the interface the function "GetInventoryCountByCategory" and has passed into the function a categoryID.

    Reason for developing with this model is to provide a mechanism for changing data providers; for example moving from .NETTIERS to LLBLGEN or LINQ while maintaining control over what methods, properties are exposed from the DAL to the BLL.  Another reason for this model is it provides a means of creating a Mock DAL to Unit test our methods with out interacting with the Database.  This is a key factor when integrating your unit tests into the CI Builds in TFS (Team Foundation Server).  Now you might be thinking to yourself that the Data layer providers such as .NETTIERS, SubSonic, and LLBLGEN provide means of unit testing through mock objects or that you could use RhinoMock and other Mock Object frameworks to mock your objects and DAL with much more functionality.  Well you maybe right, but that also comes with larger overhead and a large amount of functionality that isn't needed. 

    Now that we've had a look at the base of our provider model, lets look at some code and the differences between the two providers in diag1 (diagram above).

    As you examine the code below you will notice that both providers implements the Function GetInventoryCountByCategory, however they do so in different ways.  The NorthwindProvider is our "custom" DAL which queries the Northwind DB to get the count of products based upon the categoryID and then returns that count.  While the Mock simply takes the categoryID and then returns an integer value based from the select case statement.  We'll look more into the how we set this up as a unit test in a moment.

    IProvider.VB

    .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
       1: Public Interface IProvider
       2:     Function GetInventoryCountByCategory(ByVal CategoryID As Integer) As Integer
       3: End Interface

    TCNorthwindProvider.vb .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

       1: Imports System
       2: Imports System.Data
       3: Imports System.Data.Sql
       4: Imports System.Data.SqlClient
       5:  
       6: Public Class TCNorthwindProvider
       7:     Implements IProvider
       8:  
       9:  
      10:     Public Function GetInventoryCountByCategory(ByVal CategoryID As Integer) As Integer Implements IProvider.GetInventoryCountByCategory
      11:         Dim count As Integer
      12:         Dim sqlText As String = "SELECT Count(productID) FROM Products WHERE CategoryID = @CategoryID"
      13:         Dim sqlCommand As New SqlCommand(sqlText, GetConnection)
      14:  
      15:         With sqlCommand
      16:             .CommandType = CommandType.Text
      17:             .Parameters.AddWithValue("@categoryID", CategoryID)
      18:             .CommandText = sqlText
      19:  
      20:             Dim dr As SqlDataReader = .ExecuteReader
      21:  
      22:             While dr.Read()
      23:                 count = dr(0)
      24:             End While
      25:             dr.Close()
      26:         End With
      27:  
      28:         Return count
      29:     End Function
      30:  
      31:     Private Function GetConnection() As SqlClient.SqlConnection
      32:         Dim oConn As New SqlClient.SqlConnection
      33:         oConn.ConnectionString = "Data Source=8X5SGF1;Initial Catalog=Northwind;Integrated Security=True"
      34:         oConn.Open()
      35:  
      36:         Return oConn
      37:     End Function
      38:  
      39:    
      40: End Class
    TCNorthwindMock.vb
       1: Public Class TCNorthwindMock
       2:     Implements IProvider
       3:     Public Function GetInventoryCountByCategory(ByVal CategoryID As Integer) As Integer Implements IProvider.GetInventoryCountByCategory
       4:         Select Case CategoryID
       5:             Case 1
       6:                 Return 3
       7:             Case 2
       8:                 Return 5
       9:             Case 3
      10:                 Return 7
      11:             Case 4
      12:                 Return 6
      13:             Case 5
      14:                 Return 4
      15:             Case 6
      16:                 Return 2
      17:             Case 7
      18:                 Return 0
      19:             Case 8
      20:                 Return 1
      21:         End Select
      22:     End Function
      23:  
      24:     
      25: End Class

    Now lets take a moment to look at the offloader/worker design pattern. 

    Offloader/Worker

    offloader-worker

     

     

     

     

     

     

     

    What you'll notice when looking at this design pattern is that both the Offloader and Unittest (TCNorthwindMethodsTest) pass the work to the worker which in this case is (TCNorthwindMethods).  What this does for us, is allows us to write Unit tests for our worker methods directly, and gives us a single point of entry into the Business logic for the application.  This single point of entry will help with the trouble shooting and the maintenance aspects of the application.  Each method in the Worker class is dependent upon the provider being passed in.  Lets take a quick look at the worker class, Offloader class and unit test to see how they each work together.

     

    Worker Class

    You will notice in the worker class that we are passing in the provider and then calling the appropriate method in the provider and returning back to the offloader.  This is an example of a provider dependency injection.  There are other types of dependency injections which we will discuss some other time.  For now lets move down to the Offloader and Unit test to see how we work with the Worker class to achieve our results.

       1: Public Class TCNorthwindMethods
       2:     Public Function GetInventoryCountByCategory(ByVal categoryID As Integer, ByVal Provider As IProvider) As Integer
       3:         Return Provider.GetInventoryCountByCategory(categoryID)
       4:     End Function
       5:     Public Function GetProductsByCategoryID(ByVal categoryID As Integer, ByVal Provider As IProvider) As Products
       6:         Return Provider.GetProductsByCategoryID(categoryID)
       7:     End Function
       8:  
       9: End Class

     

    Offloader Class

    Here you will notice that we are defining 2 private members.

    • TCMethods: Our worker class
    • TCNorthWindProvider: Our Provider

    Looking at Line #7 you will see that we are calling GetInventoryCountByCategory in our worker class and passing in which the provider we want to use.  Contrast this against how we are accessing the same method in our unit test.

       1: Public Class TCNorthwindOffLoader
       2:  
       3:     Private TCMethods As New TCNorthwindMethods
       4:     Private TCNorthWindProvider As New TCNorthwindProvider
       5:  
       6:     Public Function GetInventoryCountByCategory(ByVal CategoryID As Integer) As Integer
       7:         Dim iCount As Integer = TCMethods.GetInventoryCountByCategory(CategoryID, TCNorthwindProvider)
       8:         Return iCount
       9:     End Function
      10:     Public Function GetProductsByCategoryID(ByVal CategoryID As Integer) As Products
      11:         Dim products As Products = TCMethods.GetProductsByCategoryID(CategoryID, TCNorthwindProvider)
      12:         Return products
      13:     End Function
      14:  
      15: End Class

     

    Unit Test

    Looking at our unit test, you will see in our first test method on line #20 we are setting a private member to our provider model.  In this case its our mock model we created earlier.  Now look at line #36 where we are setting a local member to our worker class and then at line 43 where we pass the provider into our worker class.  In this unit test we are hard coding in the value of our categoryID and what our expected return value is.  We will then compare the expected return value against the actual return value to determine if the test passed.  This type of Unit testing is used to determine if our logic / design is going to give us the results we need for the application and wether or not we need to redesign the application before we've accumulated to much technical debt.

       1: 'The following code was generated by Microsoft Visual Studio 2005.
       2: 'The test owner should check each test for validity.
       3: Imports Microsoft.VisualStudio.TestTools.UnitTesting
       4: Imports System
       5: Imports System.Text
       6: Imports System.Collections.Generic
       7: Imports TCNorthwindClass
       8: Imports TCNorthwindClass.TCNorthwindOffLoader
       9:  
      10:  
      11: '''
      12: '''This is a test class for TCNorthwindClass.TCNorthwindMethods and is intended
      13: '''to contain all TCNorthwindClass.TCNorthwindMethods Unit Tests
      14: '''
      15:  _
      16: Public Class TCNorthwindMethodsTest
      17:  
      18:  
      19:     Private testContextInstance As TestContext
      20:     Private tcNorthWindMock As New TCNorthwindMock
      21:  
      22:     Public Property TestContext() As TestContext
      23:         Get
      24:             Return testContextInstance
      25:         End Get
      26:         Set(ByVal value As TestContext)
      27:             testContextInstance = value
      28:         End Set
      29:     End Property
      30:  
      31:     '''
      32:     '''A test for GetInventoryCountByCategory(ByVal Integer)
      33:     '''
      34:      _
      35:     Public Sub GetInventoryCountByCategoryTest()
      36:         Dim target As TCNorthwindMethods = New TCNorthwindMethods
      37:  
      38:         Dim categoryID As Integer = 3 'TODO: Initialize to an appropriate value
      39:  
      40:         Dim expected As Integer = 7
      41:         Dim actual As Integer
      42:  
      43:         actual = target.GetInventoryCountByCategory(categoryID, tcNorthWindMock)
      44:  
      45:         Assert.AreEqual(expected, actual, "TCNorthwindClass.TCNorthwindMethods.GetInventoryCountByCategory did not return th" & _
      46:                 "e expected value.")
      47:     End Sub
      48:  
      49:  
      50:  
      51:     '''
      52:     '''A test for GetProductsByCategoryID(ByVal Integer, ByVal TCNorthwindClass.IProvider)
      53:     '''
      54:      _
      55:     Public Sub GetProductsByCategoryIDTest()
      56:         Dim target As TCNorthwindMethods = New TCNorthwindMethods
      57:  
      58:         Dim categoryID As Integer = 3 'TODO: Initialize to an appropriate value
      59:  
      60:  
      61:  
      62:         Dim expected As New Products
      63:         For i As Integer = 0 To categoryID
      64:             Dim tProduct As New Product
      65:             With tProduct
      66:                 .ProductID = i
      67:                 .ProductName = String.Format("Item{0}", i)
      68:                 .QuantityPerUnit = i.ToString
      69:                 .ReorderLevel = i
      70:                 .Discontinued = False
      71:             End With
      72:             expected.product.Add(tProduct)
      73:         Next
      74:  
      75:  
      76:  
      77:         Dim actual As Products
      78:  
      79:         actual = target.GetProductsByCategoryID(categoryID, tcNorthWindMock)
      80:  
      81:         Assert.AreEqual(expected.product.Count, actual.product.Count, "TCNorthwindClass.TCNorthwindMethods.GetProductsByCategoryID did not return the ex" & _
      82:                 "pected value.")
      83:        
      84:  
      85:         
      86:     End Sub
      87: End Class

     

     The final bit of code I want to look at is a webservice I created to use the offloader class to utilize with in the application.

    Here you will see that we have created a private member to our offloader and are passing in the categoryID to the offloader which then returns the results.

       1: Imports System.Web.Services
       2: Imports System.Web.Services.Protocols
       3: Imports System.ComponentModel
       4: Imports TCNorthwindClass
       5:  
       6: Namespace:="http://tempuri.org/")> _
       7: 
       8: False)> _
       9: Public Class TCNorthwindService
      10:     Inherits System.Web.Services.WebService
      11:     Private tcWorker As New TCNorthwindOffLoader
      12:      _
      13:     Public Function GetInventoryCountByCategory(ByVal CategoryID As Integer) As String
      14:  
      15:         Return tcWorker.GetInventoryCountByCategory(CategoryID)
      16:     End Function
      17:      _
      18:         Public Function GetProductsByCategoryID(ByVal CategoryID As Integer) As Products
      19:         Return tcWorker.GetProductsByCategoryID(CategoryID)
      20:     End Function
      21:  
      22:  
      23: End Class

     For further information and to demonstrate the actual creation and running of a unit test, please refer to the 3 screen casts linked below.

    Thank You

    David Yancey 

    Part 1
    http://www.screencast.com/t/PRz3QnkoP

    Part 2
    http://www.screencast.com/t/3SGkZ9Os

    Part 3
    http://www.screencast.com/t/3iC1qSDXXXu
  • .NET 2.0 upgrade to 3.5 bug with LINQ

    Mark Richman has found a solution to a bug when upgrading a .NET 2.0 Compiled site to .NET 3.5  and using LINQ.

    Check it out

    http://markrichman.com/post/Visual-Studio-2008-Bug-Upgrading-web-site-from-Visual-Studio-2005-compiler-error-CS1519.aspx

     Enjoy

  • XMLSerializer in C#

    A few days ago I was asked to do a version of my XMLSerializer post in C#. 

    Well it was more like a week or two ago but either way here it is.  For explanation on what I'm doing in the code please refer back to my original post.

    http://weblogs.asp.net/davidyancey/archive/2008/01/23/writing-xml-with-xmlserializer.aspx

    Download

     

  • Create a RSS Reader in .NET 3.5 using XLINQ

    Visual Studio 2008 and .NET 3.5 are finally out and with it we have some new "toys" to look at.  Today we are going to look at XLINQ and the new ListView control while we build a new RSS Reader.  Before we get started I want to take a brief at LINQ.

    LINQ (Language Integrated Query) defines a set of operators used to query, filter, and project data.  While the data must be encapsulated as an object, its source can be an array, enumerable class, XML, relational database, or any third party data source.  Some of the operators we have will be familiar to SQL programmers such as Select, Where, Join, Concat, OrderBy, Disctinct, and Union.  We will look at the syntax in a bit.  For further reading on LINQ be sure to check out the LINQ Project at Microsoft.

    To get started we are going to need:
    .NET 3.5 Framework
    Visual Studio 2008

    So lets get started by opening our development environment VS2008 and create a new Web project. 
    In this project we are going to add the following:
    Rss.vb (Class file)
    GetRss.vb (Class file)
    rss-reader.ascx (User Control)

    Rss.vb

    Looking at the code below I want to talk mainly about the LINQ portion.  But before we get going on it lets take a brief look at XDocument. In LINQ to XML (XLINQ) we use XDocument or XElement to load the XML into an object for us to query.  XDocument uses XMLReader as its underlying object to read the XML document and thus requires an XMLReader, TextReader, or URI to be passed into XDocument.  Once we have it loaded we will access it through the Descendants Method and Element Method. 

    As you look closer at the query you can see that we are loading the node "channel" into an Anonymous type . 

    myFeed In feedSource.Descendants("channel")

    By using an Anonymous type we don't have to define a class declaration of the type.  We can instead use this type inline and access the elements of the node(s) we loaded into it and set them to properties of our collection with out having to define the properties.

    feedDescription = myFeed.Element("description").Value

    We can also create a sub collection with in our query and return it as part of the object to later be processed.

    feedItems = myFeed.Descendants("item")

    We finally we are returning our query as IEnumerable object to later be bound to a Listview in our class control.

     

    Public Class RSS
        Public Function Read(ByVal URLPath As String) As IEnumerable
            Dim dcNameSpace As XNamespace
            dcNameSpace = XNamespace.Get("http://purl.org/dc/elements/1.1/")
            Dim feedSource As XDocument
            feedSource = XDocument.Load(URLPath)
    
            Dim query = From myFeed In feedSource.Descendants("channel") _
                        Select feedTitle = myFeed.Element("title").Value, _
                                feedDescription = myFeed.Element("description").Value, _
                                feedLink = myFeed.Element("link").Value, _
                                feedAuthor = myFeed.Element(dcNameSpace + "creator").Value, _
                                feedItems = myFeed.Descendants("item")
            Return query
        End Function
    End Class


    GetRss.vb

    This is a simple class.  We are passing in URLPath (URL to our Feed) to be processed.  As you can see we call the read method of our RSS object (our DAL) and return it to our class control.  This class file is our BLL.  It is in this layer we would apply any business rules needed.

    Public Class GetRSS
        Private m_urlPath As String
        Public Function GetRSS() As IEnumerable
            Dim myRSS As New RSS
    
    
            Return myRSS.Read(m_urlPath)
        End Function
    
        Public Sub New()
    
        End Sub
    
        Public Sub New(ByVal UrlPath As String)
            m_urlPath = UrlPath
        End Sub
    End Class

    Rss-Reader.ascx

    Now to the fun part of putting it all together.  First the code behind. 

    Simply we set a property for the class to hold URLpath, and bind the object to the our list view in our page_load.  However we have another method in our codebhind that I'm calling XEval.  The problem here is the sub collection inside our IEnumerable object.  When we get the collection at this point we are finding 2 main property's exposed.  One is value, and the other is XML.  We will see how we use both of these when we look at the markup.  Briefly though Value gives us the value of the property, and XML gives us the XML markup of that same property.  Neither of which are queriable (that I was able to find).  So what we are doing in XEval is passing the XML property to this method, along with the Xpath we want to return the InnerText of that node.

    Imports System.Xml
    Partial Public Class rss_reader
        Inherits System.Web.UI.UserControl
    
        Private m_urlPath As String
        Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            Dim myRSS As New GetRSS(m_urlPath)
            listview1.DataSource = myRSS.GetRSS
            listview1.DataBind()
    
        End Sub
    
        Public Function xEval(ByVal x As String, ByVal xPath As String) As String
            Dim xDocument As New XmlDocument
            xDocument.LoadXml(x)
    
            x = xDocument.SelectSingleNode(xPath).InnerText
            Return x
        End Function
    
        Public Property URLPath() As String
            Get
                Return Me.m_urlPath
            End Get
            Set(ByVal value As String)
                Me.m_urlPath = value
            End Set
        End Property
    
    End Class

    Now the markup.

    Here I want to look at the ListView.  ListView's can be bound to an object that Inherits IEnumerable, SQLDatasource, LINQDatasource, XMLDatasource, and ObjectDatasource.  In our ListView we are using the LayoutTemplate which has a placeholder inside of a div and the ItemTemplate.  There are other templates available to us such as AlternateItemTemplate, HeaderTemplate, FooterTemplate, and EmptyItemTemplate.  Each of these templates will be rendered into the placeholder in the layout template.  So as you can see this gives us flexability in defining the look and feel of our control.  Scott Guthrie has a great blog entry giving more information on ListView's.  For mine here I'm a CollapsiblePanelExender control from Ajax to provide a bit of control and styling.

    <%@ Control Language="vb" AutoEventWireup="false" CodeBehind="rss-reader.ascx.vb" Inherits="Sandbox.rss_reader" %>
    <%@ Register assembly="AjaxControlToolkit" namespace="AjaxControlToolkit" tagprefix="cc1" %>
    
    <asp:ListView ID="listview1" runat="server">
                <LayoutTemplate>
                    <div style="width: 1000px;">
                        <asp:PlaceHolder ID="itemPlaceHolder" runat="server" />
                    </div>
                </LayoutTemplate>            
                <ItemTemplate>
                    <div>
                        <asp:Hyperlink ID="hlin2" runat="server" style="font-weight: bold; font-size: 12pt; color: Black;" Text='<%# Eval("feedTitle") %>' NavigateUrl='<%# Eval("feedLink") %>' />
                    </div>
                    <div>    
                        <asp:Label ID="label1" runat="server" style="font-weight: bold; font-size: 12pt;" Text='<%# Eval("feedDescription") %>' />
                    </div>
                    <div><hr /></div>           
                    <div>
                        <asp:ListView ID="listview2" runat="server"  DataSource='<%# Eval("feedItems") %>' >
                            <LayoutTemplate>
                                <div>
                                    <asp:placeHolder ID="itemPlaceHolder" runat="server" />
                                </div>
                            </LayoutTemplate>
                            <ItemTemplate>
                                <div>
                                    <div id="descriptControl" runat="server" style="height: 30px;">
                                    <div style="float: left;">
                                        <asp:HyperLink ID="hlink1" runat="server" Text='<%# xEval(Eval("XML"), "/item/title") %>' NavigateUrl='<%# xEval(Eval("XML"), "/item/link") %>' />
                                    </div>
                                    <div style="float:right;">
                                        <asp:ImageButton ImageUrl="~/expand.jpg" ID="imgbtn" runat="server" />
                                    </div>
                                    </div>                                
                                   <asp:Panel ID="panel1" runat="server" BorderStyle="Inset" BorderColor="#333333" BorderWidth="1">
                                        <div>
                                            <asp:Label ID="label2"  style="font-size: 9pt; font-style:italic; color: Gray;" runat="server" Text='<%# xEval(Eval("XML"), "/item/pubDate") %>' />
                                        </div>
                                        <div id="descriptDiv" runat="server" style="padding: 3px;">
                                            <asp:Label ID="label3"  style="font-size: 9pt;" runat="server" Text='<%# xEval(Eval("XML"), "/item/description") %>' />
                                        </div>
                                    </asp:Panel>
                                    <cc1:CollapsiblePanelExtender ID="CollapsiblePanelExtender1" runat="server" Collapsed="true" 
                                        TargetControlID="panel1" ExpandControlID="imgbtn" CollapseControlID="imgbtn"
                                         CollapsedImage="expand.jpg" ExpandedImage="collapse.jpg" SuppressPostBack="true">
                                    </cc1:CollapsiblePanelExtender>
                                </div>         
                            </ItemTemplate>
                        </asp:ListView>
                    </div>        
                </ItemTemplate>
            </asp:ListView>
    And the final output:
     
    image
     

     

    Download Sourcecode

     

    That's all for now.

    Next time we will look at building an XML Document using XDocument and XElement.

    Dave

  • Create a customized RSS Reader for your site

    RSS definition From Wikipedia

    "RSS (formally "RDF Site Summary", known colloquially as "Really Simple Syndication") is a family of Web feed formats used to publish frequently updated content such as blog entries, news headlines or podcasts. An RSS document, which is called a "feed", "web feed", or "channel", contains either a summary of content from an associated web site or the full text. RSS makes it possible for people to keep up with their favorite web sites in an automated manner that's easier than checking them manually.

    RSS content can be read using software called an "RSS reader", "feed reader" or an "aggregator". The user subscribes to a feed by entering the feed's link into the reader or by clicking an RSS icon in a browser that initiates the subscription process. The reader checks the user's subscribed feeds regularly for new content, downloading any updates that it finds."

    What I call it is a great way to get my news.  I've got 4 feeds that I read in my Outlook daily.  On my blog I have 4 other feeds including one of my own.  You see them on almost every news site, blog, forum, website you visit.  So why a blog entry on RSS Readers?  Well the problem is that there aren't many options to add an aggregator so that you can display your favorite feeds on your site for your visitors.  So today we are going to take a little bit of .NET and add some XSLT and finally throw in a few features to display the feed on your community website.

    So lets get started.  First add a user control to your project.  Here in our control you can see that we are simply using an XSLCompiledtransform object to transform the feed.  You will also notice that we have added a property to our user control so that we could set the path to the feed at runtime.

    Imports System.Xml
    Imports System.Xml.Xsl
    Imports System.IO
    
    Partial Public Class ucBlogReader
        Inherits System.Web.UI.UserControl
    
        Private m_xmlURL As String
        Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            LoadBlog(m_xmlURL)
        End Sub
    
        Protected Sub LoadBlog(ByVal path As String)
            If path = "" Then
                XMLBlogReader.Text = "Please select a blog from the left"
            Else
                Dim myXSL As New XslCompiledTransform
                Dim tempStringWriter As New StringWriter
                Dim tempString As XmlWriter = New XmlTextWriter(tempStringWriter)
    
                myXSL.Load(Server.MapPath("~/XSL/rss-reader.xslt"))
    
                myXSL.Transform(path, tempString)
    
                Me.XMLBlogReader.Text = tempStringWriter.ToString()
    
            End If
        End Sub
    
        Public Property XMLUrl() As String
            Get
                Return m_xmlURL
            End Get
            Set(ByVal value As String)
                m_xmlURL = value
            End Set
        End Property
    
    End Class

    XSLT

    Now comes the fun part.  Once we have our RSS feed we have various options to transform it.  We could use XMLDocument, XMLReader, or XMLDatasourse and many other options to traverse the feed.  For this example we are going to build the XSLT we use in the code above to transform our RSS Feed.  

    There are two key parts that I want to point out in our XSLT document.

    The first being our loop.  Here we are testing the position of each "item" node with in the XPATH statement.  When that position is greater than 5 we exit the loop. 

    <xsl:for-each select="rss/channel/item[position()&lt;=5]"

    The second area I wanted to look at is where we display the "description" node.  What we are doing here is taking the first 500 characters of the description using the substring function with in XPATH. 

    <xsl:value-of select="substring(description, 1, 500)" disable-output-escaping="yes"/>

    There are many different ways of building an XSLT document, such as building a template for the title, description, links etc...  In our example we are just creating a single template and keeping our document as simple as possible. 

    <?xml version="1.0" encoding="UTF-8" ?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
      xmlns:dc="http://purl.org/dc/elements/1.1/">
      <xsl:output method="xml"/>
      <xsl:template match="/">
        <Div id="wrap">
          <Div style="text-align: left;">
            <xsl:attribute name="id">title</xsl:attribute>
            <H3>
            <xsl:value-of select="//dc:creator" />
            </H3>
          </Div>
          <Div>
            <xsl:attribute name="id">
              content:<xsl:value-of select="rss/channel/title" />
            </xsl:attribute>
            <xsl:for-each select="rss/channel/item[position()&lt;=5]">
              <P style="text-align: left;">
                <A>
                  <xsl:attribute name="href">
                    <xsl:value-of select="link"/>
                  </xsl:attribute>
                  <xsl:attribute name="style">
                    color: black; font-weight: bold;
                  </xsl:attribute>
                  <xsl:attribute name="target">_new</xsl:attribute>
                  <xsl:value-of select="title"/>
                </A>
                <br/>
                <xsl:value-of select="pubDate"/>
                <br/>
              </P>
              <Div style="text-align: left; padding-top: 10px; padding-bottom: 5px; padding-left: 15px;">
                <xsl:value-of select="substring(description, 1, 500)" disable-output-escaping="yes"/>
                <xsl:text>...</xsl:text>
              </Div>
            </xsl:for-each>
          </Div>
        </Div>
      </xsl:template>
    </xsl:stylesheet>

    The final step is to add your new control to your site and set the value of the XMLUrl property to the URL of your desired feed.  I'm going to leave that with you to accomplish, however if you would like to see our new control working, you can do so at http://www.proessent.com/blog.aspx

    That's it for now.  Check back next week when we will look at building another RSS Reader using LINQ in Visual Studio 2008.

    See you on the Flip Side

    Dave

    xml vb.net asp.net

     

  • Building a TreeView of your Directory Structure using XML, WebServices, and Delegates

    TreeViews provide a great way for displaying a hierarchal view of a website, directory, company, and the list goes on.  You can build a TreeView by binding it to a datasource, or by manually adding the nodes.  Today we are going to look at building a TreeView of a directory structure for a website.  To do this we are going to create a WebService that utilizes Delegates to traverse the directory and return an XMLDocument to our web page which will then be bound to our TreeView.

    First off lets take a quick look at why we are using a delegate when traversing the directory.  We could have just created a method that returns all the folders using Directory.GetDirectories and then process them all in a loop.  However; if the path being traversed contains thousands of items, then the application will most likely freeze and ignore any input from the user.  What delegates does is provides for us a way to traverse the directory and build our xml through a callback function thus giving control back to the user while this is taking place. 

    WebService : DirectoryInfoView

    <WebMethod()> _
        Public Function GetDirectoryInfo(ByVal path As String, ByVal sessionguid As String) As XmlDocument
            Dim tmpDocument As New XmlDocument
            If Not sessionguid = Session("wscall").ToString Then
                Throw New Exception("Security Exception:  You are not allowed to access this service")
            End If
            xmlWriter.Formatting = Formatting.None
            xmlWriter.WriteProcessingInstruction("xml", "version='1.0' encoding='UTF-16'")
            xmlWriter.WriteStartElement("SiteMapNode")
            xmlWriter.WriteAttributeString("url", path)
            xmlWriter.WriteAttributeString("title", (New DirectoryInfo(path).Name))
            TraverseDirectoryTree(path, AddressOf AddDirName)
            xmlWriter.Close()
            tmpDocument.LoadXml(UTF8ByteArrayToString(memStream.ToArray()))
            Return tmpDocument
        End Function
    
        Private Delegate Sub TraverseDirectoryTreeCallBack(ByVal dirName As String)
    
        Private Sub TraverseDirectoryTree(ByVal path As String, ByVal cbk As TraverseDirectoryTreeCallBack)
            For Each fileName As String In Directory.GetFiles(path)
                cbk.Invoke(fileName)
                xmlWriter.WriteEndElement()
            Next
            For Each dirName As String In Directory.GetDirectories(path)
                cbk.Invoke(dirName)
                TraverseDirectoryTree(dirName, cbk)
            Next
            xmlWriter.WriteEndElement()
        End Sub
    
        Private Sub AddDirName(ByVal path As String)
            xmlWriter.WriteStartElement("SiteMapNode")
            xmlWriter.WriteAttributeString("url", path)
            xmlWriter.WriteAttributeString("title", (New DirectoryInfo(path).Name))
        End Sub
    
        Private Function UTF8ByteArrayToString(ByVal characters As Byte()) As String
    
            Dim encoding As New UTF8Encoding()
            Dim constructedString As String = encoding.GetString(characters)
            Return (constructedString)
        End Function

    Default.aspx

    Here we call our webservice and bind it to an XMLDataSource.  You will also notice in our TreeView how we are binding the TreeNode to the XML.

    Private Sub GetDirectoryInfo(ByVal path As String)
        Dim ws As New DirectoryInfoView
        Dim treeNode As New TreeNodeBinding
        Me.XmlDataSource1.Data = ws.GetDirectoryInfo(path, Session("wscall").ToString).OuterXml
        Me.XmlDataSource1.DataBind()
    End Sub

     

    <asp:TreeView ID="TreeView1" runat="server" DataSourceID="XmlDataSource1">
        <DataBindings>
            <asp:TreeNodeBinding DataMember="SiteMapNode" ValueField="url" TextField="title" />
        </DataBindings>              
    </asp:TreeView>
    <asp:XmlDataSource ID="XmlDataSource1" runat="server"></asp:XmlDataSource>

     

    Giving us a final result of.

    image

    Project File DirectoryTreeView

    xml webservices .net vb.net

  • Create a Who's Online using .NET's Membership Provider!

    Developing and maintaining a community website can sometimes be a daunting task.  A great deal of thought, and planning needs to go into creating content for your community to view, experience, and interact with.  One fun piece that you will find on a number of community webistes is a "Who's Online".  This is just a little bit of content that tells you how many registered users you have, how many registered users are online, how many guests are online, and the usernames of the registered users online. 

    So today we are going to create a usercontrol that will display who's online, in either a Horizontal or Vertical Format.

    Start off with adding a usercontrol to your project with a label, and then in the codebehind we want to create a property and enum to set the orientation of our control.

    Public m_Orientation As orientation
    
    Public Enum orientation As Integer
        Horizontal = 1
        Vertical = 2
    End Enum
    
    Public Property Orientate() As orientation
        Get
            Return m_Orientation
        End Get
        Set(ByVal value As orientation)
            m_Orientation = value
        End Set
    End Property
    .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

    Now the trick to this control is getting the count of our guests online.  We have a couple of options to do this, one of which would be to store the session in a table and then getting the count from the table.  However I didn't like going with that method.  To much work.  So what we are going to do is store a count in the cache each time a new session is started.  And decrease that count when the session ends.  So lets move over to the global.asax and set this up.

    Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
        'Initialize user count 
        HttpContext.Current.Cache.Insert("UserCount", 0)
    End Sub
    
    Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
        ' Fires when the session is started
        HttpContext.Current.Cache("UserCount") += 1
    End Sub
    
    Sub Session_End(ByVal sender As Object, ByVal e As EventArgs)
        ' Fires when the session ends
        HttpContext.Current.Cache("UserCount") -= 1
    End Sub
    
    Sub Application_End(ByVal sender As Object, ByVal e As EventArgs)
        'Dont forget to clean up
        HttpContext.Current.Cache.Remove("UserCount")
    End Sub

    Now heading back to our usercontrol lets do the work that builds the counts. To get the count of registered users online we call Membership.GetNumberOfUsersOnline, we then just take that count and subtract it from the "UserCount" we have stored in our cache to get the count of guests online. As you can see we are using Membership.GetAllUsers.Count to get our total registered users count and looping through GetAllUsers to get the  UserName of each member online. 

     
    Private Sub GetWhosOnline()
        Dim delimeter As String = "<br />"
        Dim guestCount As Integer
        Select Case m_Orientation
            Case orientation.Horizontal
                delimeter = " | "
            Case orientation.Vertical
                delimeter = "<br />"
        End Select
        If (HttpContext.Current.Cache("UserCount") IsNot Nothing) Then
            guestCount = CInt(HttpContext.Current.Cache("UserCount").ToString()) - CInt(Membership.GetNumberOfUsersOnline.ToString)
        End If
        Me.lblWhosOnline.Text = String.Format("Total Registered: {0}{1}", Membership.GetAllUsers.Count, delimeter)
        Me.lblWhosOnline.Text += String.Format("Total Online: Registered ({0}): Guests({1}){2}", _
    Membership.GetNumberOfUsersOnline.ToString, guestCount, delimeter) Me.lblWhosOnline.Text += "Who's Online: " For Each memberUser As MembershipUser In Membership.GetAllUsers If Membership.GetUser(memberUser.UserName).IsOnline Then Me.lblWhosOnline.Text += memberUser.UserName & ", " End If Next lblWhosOnline.Text = Left(lblWhosOnline.Text, Len(lblWhosOnline.Text) - 2) End Sub

    Now all we need to do is to include the usercontrol on a page, and set the our property for how we want it displayed.

    <uc1:ucWhosOnline id="UcWhosOnline1" runat="server" Orientate="Vertical"  />

    .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

    And now you have a "Who's Online" usercontrol for your community website.

    Enjoy,

    Dave

    .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

    Technorati Tags: ,
More Posts Next page »
Copyright FWDNUG 2008
Powered by Community Server (Commercial Edition), by Telligent Systems