October 2007 - Posts

ASP.NET is designed to create dynamic web pages by combining data from a database with HTML. Perhaps it would be more accurate to say it programmatically generates web pages for immediate delivery by the web server. That is the basic concept. As I have been working with video for the web instead of HTML for the web it has occurred to me that it would be cool to apply the same concept to video. I would call it ASV.NET (Active Server Video).

Video editing and production is a tedious process and could benefit from some automation. I've spent about a year learning Adobe After Effects which is used to create motion graphics. Think of it as Photoshop for video. Creating a composition in After Effects involves some of the same elements as creating a web page in HTML. First you create some title scenes using text and then you insert some scenes using images or video footage. I actually create a lot of videos using just text and images because you can animate them both.

After Effects does offer some options for programmatically generating video content but these features are rarely mentioned because video editors aren't very keen on programming. Expressions are written in JavaScript and allow you to base one parameter value like rotation on another parameter value like position. However, if you get the Professional version of After Effects you also get the ability to script the After Effects application using JavaScript. This is similar to Visual Basic for Applications. Microsoft products tend to use VBScript for scripting automation while non-Microsoft products tend to use JavaScript. Other examples of software products with scripting abilities include; Ultra-Edit, Photoshop, and Paint Shop Pro which uses Python I think. I was looking though the After Effects Scripting Guide PDF last night and saw that its implementation of JavaScript allows you to access the file system, create user interface elements, apply an effect to a layer, write text to the info palette, send email, and even issue HTTP Get requests using a socket object. That last item got me excited! You can establish a connection to a web server and retrieve data using a Get request! This means that you could theoretically pull data from a web service and use it in your video composition. For example, you could get headlines from a RSS feed and create your title scenes using current news headlines.

There are some plug-ins available for After Effects that seem to serve the purpose of pulling in data from external sources for use in the video composition. Digital Anarchy's Screen Text plug-in can be used to read in text and I think they have a charting plug-in which I have not tried.

Last night I also briefly examined Microsoft Expression Blend to see if it could be used to apply the concept of Active Server Video. Expression Blend supports some similar features as After Effects such as keyframe animation and the use of vector graphics. However, it was clearly based on the Adobe Flash Professional multimedia authoring program and is not intended for professional video compositing. I've tried to use Flash animation to create videos but it is definitely not the right tool for the job. In other words, Expression Blend is an authoring program for Silverlight, the Microsoft alternative to Flash. I was intrigued that it supports databinding and can be used with Visual Studio but it has no video editing capabilities and its animation capability does not apply to video.

Dynamically generating video would merely save time in the content creation process but combined with streaming media it could offer immediate delivery of current data. Various data feeds from web services, developer APIs, and RSS feeds could be scrolled along the bottom of a video stream just like news headlines on a news channel. Video content could also be dynamically generated upon request much like an ASP.NET text content page but the video rendering time may be a problem.

I am very active in the vlogging community at YouTube and Stickam. Vlogging is clearly the future of online communication and social networking sites. I have been particularly impressed by how effective vlogging is for forming genuine friendships and online community. I've always been an anti-social IT geek and I never appreciated the value of social networking sites until I found YouTube where you can see and hear the people you are communicating with. Many of the YouTube vloggers are addicted to video conferencing on the Stickam web site. I have witnessed many instances of vloggers collaborating with each other on video projects. It would be interesting if there were a social networking site for developers that used video to forge an effective online community for collaboration. I do have an account on ITtoolbox which is a professional networking site for IT geeks but it lacks any video sharing capabilities and therefore does not create a real sense of community.

I've invested a lot of time in learning video editing and motion graphics software. I plan to do some really innovative work to combine my programming experience with video production. With the Internet becoming a multimedia platform, there will be a need to combine data dynamically with video elements just as ASP.NET is used to dynamically combine data with HTML code as text.

After YouTube was bought by Google, they switched their developer's API to the Google Data API. The Google Data API has a client library for .NET but it does not include the YouTube GData service yet. This is not too much of a problem because you are just consuming a XML data feed. As usual, I had a great deal of difficulty finding the correct XPath for a particular XML node but I've found an excellent free tool to help with this problem. The Liquid XML Studio 2008 from Liquid Technologies is a free download that has a handy XPath Query Builder. It even generates the C# code you need to properly reference the target XML node. You can even generate the XSL which is really awesome!

YouTube is frequently deleting user accounts for vloggers because they upload videos containing copyrighted material or violate the terms of service. So I wanted to use the Google Data API to save my account information to my own database as a back up in case I lose my account. I've written a C# Windows application to save my video favorites into a SQL Server database table. I saw no reason to do this in ASP.NET but there is a lot of HTML in the video description that you may want to include in a web page. You can only retrieve 50 results at a time so it was necessary to determine how many requests to make, varying the start-index parameter.

private void btnBackUp_Click(object sender, EventArgs e)
        {
            
try
            {
                
Uri HttpSite = new Uri("http://gdata.youtube.com/feeds/users/robrobbins/favorites");
                
HttpWebRequest wreq = ((HttpWebRequest)WebRequest.Create(HttpSite));
                wreq.KeepAlive =
false;
                wreq.Timeout = 30000;
                
// Get the data as an HttpWebResponse object
                WebResponse resp = wreq.GetResponse();
                
StreamReader strReader = new StreamReader(resp.GetResponseStream(), System.Text.Encoding.UTF8);
                
XmlTextReader tr = new XmlTextReader(strReader);
                
XmlDocument doc = new XmlDocument();
                doc.Load(tr);
                
XmlNodeList xnl = doc.GetElementsByTagName("openSearch:totalResults");
                rtbMessage.Text +=
"Count:" + xnl.Count.ToString() + "\r\n";
                
if (xnl.Count > 0)
                {
                    intLoopCount =
Convert.ToInt32(xnl[0].InnerText);
                    intLoopCount =
Convert.ToInt32(Math.Round(intLoopCount / 50.0));
                    rtbMessage.Text +=
"[" + xnl[0].InnerText + "]" + "\r\n";
                    rtbMessage.Text +=
"Loop Count: " + intLoopCount.ToString() + "\r\n";
                }
                resp.Close();
                wreq.Abort();

                
// request 50 results at a time
                int intStartIndex = 1;
                
for (int i = 0; i < intLoopCount; i++)
                {
                    RequestFavorites(intStartIndex, 50);
                    intStartIndex = intStartIndex + 50;
                }

            }
            
catch (Exception ex)
            {
                rtbMessage.Text += ex.Source +
" " + ex.Message + " " + ex.StackTrace;
            }
        }

        
private void RequestFavorites(int intStartIndex, int intMaxResults)
        {
            
Uri HttpSite = new Uri("http://gdata.youtube.com/feeds/users/robrobbins/favorites?start-index=" + intStartIndex.ToString() + "&max-results=" + intMaxResults.ToString());
            rtbMessage.Text += HttpSite.ToString() +
"\r\n";
            
HttpWebRequest wreq = ((HttpWebRequest)WebRequest.Create(HttpSite));
            wreq.KeepAlive =
false;
            wreq.Timeout = 30000;
            
// Get the data as an HttpWebResponse object
            WebResponse resp = wreq.GetResponse();
            
StreamReader strReader = new StreamReader(resp.GetResponseStream(), System.Text.Encoding.UTF8);
            
XmlTextReader tr = new XmlTextReader(strReader);
            
XmlDocument doc = new XmlDocument();
            doc.Load(tr);
            
// Select XML nodes by namespace
            XmlNamespaceManager nsMgr = new XmlNamespaceManager(doc.NameTable);
            nsMgr.AddNamespace(
"tns", "http://www.w3.org/2005/Atom");
            
XmlNodeList xnlID = doc.SelectNodes("//tns:entry//tns:id", nsMgr);
            
XmlNodeList xnlAuthor = doc.SelectNodes("//tns:entry//tns:author//tns:name", nsMgr);
            
XmlNodeList xnlURI = doc.SelectNodes("//tns:entry//tns:author//tns:uri", nsMgr);
            
// Get XML nodes by tag name
            XmlNodeList xnlTitle = doc.GetElementsByTagName("media:title");
            
XmlNodeList xnlDescription = doc.GetElementsByTagName("media:description");
            
XmlNodeList xnlKeywords = doc.GetElementsByTagName("media:keywords");
            
XmlNodeList xnlDuration = doc.GetElementsByTagName("yt:duration");
            
XmlNodeList xnlCategory = doc.GetElementsByTagName("media:category");
            
XmlNodeList xnlViewCount = doc.GetElementsByTagName("yt:statistics");
            
XmlNodeList xnlRating = doc.GetElementsByTagName("gd:rating");
            
// declare database objects
            string strSQL = "";
            
string strCN = "Initial Catalog=YouTube; Data Source=ORPHEUS;uid=*****;pwd=****;Connect Timeout=120;Pooling=True";
            
SqlConnection objConnection = new SqlConnection(strCN);
            
SqlCommand objCommand = new SqlCommand();
            objConnection.Open();
            rtbMessage.Text +=
"xnlID Count: " + xnlID.Count.ToString() + "\r\n";
            
if (xnlID.Count > 0)
            {
                
for (int i = 0; i < xnlID.Count - 1; i++)
                {
                    strSQL =
"INSERT INTO Favorites (ID,Author,Uri,Title,Description,Keywords,Duration,Category,ViewCount,Rating) VALUES (" +
                        
"'" + xnlID[i].InnerText.Replace("'", "''") + "'," +
                        
"'" + xnlAuthor[i].InnerText.Replace("'", "''") + "'," +
                        
"'" + xnlURI[i].InnerText.Replace("'", "''") + "'," +
                        
"'" + xnlTitle[i].InnerText.Replace("'", "''") + "'," +
                        
"'" + xnlDescription[i].InnerText.Replace("'","''") + "'," +
                        
"'" + xnlKeywords[i].InnerText.Replace("'", "''") + "'," +
                        
"'" + xnlDuration[i].Attributes["seconds"].Value + "'," +
                        
"'" + xnlCategory[i].InnerText + "'," +
                        
"'" + xnlViewCount[i].Attributes["viewCount"].Value + "'," +
                        
"'" + xnlRating[i].Attributes["average"].Value + "');";
                    rtbMessage.Text += strSQL +
"\r\n";
                    objCommand.CommandText = strSQL;
                    objCommand.Connection = objConnection;
                    objCommand.ExecuteNonQuery();
                }
            }
            objConnection.Close();
            resp.Close();
            wreq.Abort();
        }
    }

I'm very enthusiastic about web parts but I've been a bit disappointed by the quality of the demonstrations and examples that are provided. Usually you are shown how to drop a calendar control into a web part zone and then there is some discussion of how the web part manager works. My general complaint with sample code is that it is either too simple and does not accomplish any task that you would find useful, or it is too complicated and you won't want to tackle it. I have had to struggle to create some web part examples that accomplish something interesting.

I'm going to share a very simple web part that will give you a better idea of how they can be used to create mash ups. My example web part gets the weather from the National Weather Service. I used a XSL file to transform the XML from the web service so there is very little code involved. You can easily combine a variety of RSS feeds and web services into a mash up site using web parts.

Weather Web Part

I've recently made some improvements to this web part. I added a textbox and a button so you can change the weather station which simply requires using a different station id in the URL. I also added the ability to set a web part property depending upon the user input. Finally, I put everything into an UpdatePanel to avoid the annoyance of a postback. I know this is really simple stuff but it is still a better example than just dumping a control on a web part zone without giving it the slightest functionality.

The WeatherWebPart is a very simple user control:

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="WeatherWebPart.ascx.cs" Inherits="WeatherWebPart" %>
<div style="font-family: Arial, 'Microsoft Sans Serif';font-size: 10pt;">
    <asp:ScriptManager ID="ScriptManager1" runat="server">
    </asp:ScriptManager>
    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>
            <asp:Xml ID="Xml1" runat="server" TransformSource="App_Data/Weather.xsl" EnableViewState="false"></asp:Xml>
            Station ID: &nbsp;<asp:TextBox ID="txtStationID" runat="server" Width="51px"></asp:TextBox>
            <asp:Button ID="btnChange" runat="server" Text="Change" />
        </ContentTemplate>
    </asp:UpdatePanel>
    <br />
</
div>

The XSL style sheet does all of the work transforming the XML into HTML. I really like using XSLT because it is very portable. I have used this very same XSL file to show the weather in DotNetNuke and Joomla:

<?xml version="1.0" encoding="utf-8"?>
<
xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<
xsl:output omit-xml-declaration="yes" method="html" />
<
xsl:template match="/">
  <!--
This is an XSL template file. -->
  <
table bgcolor="#eeeeee" cellspacing="0" cellpadding="1">
    <
tr bgcolor="lightsteelblue">
      <
td colspan="2">
        <
xsl:value-of select="current_observation/location"/>
        <
br/>
        <
xsl:value-of select="current_observation/observation_time"/>
      </
td>
    </
tr>
    <
xsl:if test="current_observation/weather != ''">
    <
tr>
      <
td>
        Weather:
      </td>
      <
td>
        <
xsl:value-of select="current_observation/weather"/>
      </
td>
    </
tr>
    </
xsl:if>
    <
xsl:if test="current_observation/temperature_string != ''">
    <
tr>
      <
td>
        Temperature:
      </td>
      <
td>
        <
xsl:value-of select="current_observation/temperature_string"/>
      </
td>
    </
tr>
    </
xsl:if>
    <
xsl:if test="current_observation/relative_humidity != ''">
    <
tr>
      <
td>
        Humidity:
      </td>
      <
td>
        <
xsl:value-of select="current_observation/relative_humidity"/> %
      </td>
    </
tr>
    </
xsl:if>
    <
xsl:if test="current_observation/wind_string != ''">
    <
tr>
      <
td>
        Wind:
      </td>
      <
td>
        <
xsl:value-of select="current_observation/wind_string"/>
      </
td>
    </
tr>
    </
xsl:if>
    <
xsl:if test="current_observation/windchill_string != '' and
    current_observation/windchill_string != 'NA'
">
    <
tr>
      <
td>
        Wind Chill:
      </td>
      <
td>
        <
xsl:value-of select="current_observation/windchill_string"/>
      </
td>
    </
tr>
    </
xsl:if>
    <
xsl:if test="current_observation/heat_index_string != '' and
    current_observation/heat_index_string != 'NA'
">
    <
tr>
      <
td>
        Heat Index:
      </td>
      <
td>
        <
xsl:value-of select="current_observation/heat_index_string"/>
      </
td>
    </
tr>
    </
xsl:if>   </table>
</
xsl:template>
</
xsl:stylesheet>
 

The code behind for the web part implements the IWebPart interface in order to set some interesting properties like the title icon:

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class WeatherWebPart : System.Web.UI.UserControl, IWebPart
{
protected string _Subtitle = "Williamsport PA";
    protected void Page_Load(object sender, EventArgs e)
    {
        System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
        try
        {
            if (!IsPostBack)
            {
                doc.Load("http://www.weather.gov/data/current_obs/KIPT.xml");
            }
            else
            {
                doc.Load("http://www.weather.gov/data/current_obs/" + txtStationID.Text + ".xml");
                switch (txtStationID.Text)
                {
                    case "KLAX":
                        this.Subtitle = "Los Angeles, CA";
                        break;
                    case "PANC":
                        this.Subtitle = "Anchorage, AK";
                        break;
                }
                Xml1.Document = doc;
            }
        }
        catch
        {
            Xml1.DocumentSource = "App_Data/Weather.xml";
        }
    }

    #region IWebPart Members

    public string CatalogIconImageUrl
    {
        get
        {
            return "~/App_Themes/Default/img/weathergov.ico";
        }
        set
        {
            return;
        }
    }

    public string Description
    {
        get
        {
            return "Local weather from NOAA's National Weather Service";
        }
        set
        {
            return;
        }
    }

    public string Subtitle
    {
        get 
        {
            return _Subtitle; 
        }
        set
        {
            _Subtitle = value;
        }
    }

    public string Title
    {
        get
        {
            return "Local Weather";
        }
        set
        {
            return;
        }
    }

    public string TitleIconImageUrl
    {
        get
        {
            return "~/App_Themes/Default/img/weathergov.ico";
        }
        set
        {
            return;
        }
    }

    public string TitleUrl
    {
        get
        {
            return "~/Default.aspx";
        }
        set
        {
            return;
        }
    }

    #endregion

     }

You may have seen the article on ASP.NET Charting with NPlot on the 4 Guys From Rolla.com web site. Unfortunately, all of the sample code provided only shows you how to create line charts. If you visit the wiki for NPlot you will only find a plea for a BarPlot tutorial. I sent an email to one of the NPlot developers asking for some sample code for creating bar charts and he provided enough code for me to figure it out. I contributed several examples of NPlot bar charts in VB.NET and C# using the Northwind database and even one using XML as the data source but these examples have not been added to the wiki. I will provide you with enough information here to create bar charts in case someone is still looking for a solution.

First copy all of the sample code from the 4 Guys From Rolla.com web site article because you only need to change a few lines. The first step is just to change the type of plot object you are creating, obvious enough:

'One Plot for each timeseries:
Dim npPlot1 As New NPlot.BarPlot
Dim npPlot2 As New NPlot.BarPlot

The tricky part that is not documented and which you cannot figure out without a clue is how to assign the data to each axis. It is slightly different from the Line Chart example:

<>'Timeseries 1 to Plot 1:
npPlot1.AbscissaData = X1
npPlot1.OrdinateDataTop = OT1
npPlot1.OrdinateDataBottom = OB1

Here OT1 and OB1 are arrays of double values and X1 is whatever data your X axis uses:

OT1 = New Double() {2, 4, 6, 4, 12, 5, 8, 1, 3, 9}
OB1 =
New Double() {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

If you use a table for your datasouce then use the columns for the axis data:

<>npPlot1.DataSource = objDataSet.Tables(0)
'Column names in the dataset were established in the SQL statement
npPlot1.AbscissaData = "AbscissaData"
npPlot1.OrdinateDataTop = "OrdinateDataTop"
npPlot1.OrdinateDataBottom = "OrdinateDataBottom"

Free Image Hosting at www.ImageShack.us

XML is being used for a lot of configuration files and to store application and system settings. It is also used extensively to define the presentation layer; Windows Presentation Foundation and Mozilla's XML User Interface Language for example. Therefore it is often useful to be able to transform XML into a more readable format for documentation.

Visual Studio 2005 uses a lot of XML files to store the DataSets and the design surface of the DataSet Designer. I am currently working on a project where I have to reconcile my DataSet with the DataSet of another developer. It is tedious to open both projects in Visual Studio and then scroll around the design surface of the DataSet Designer trying to count tables and trying to compare table adapter names. It occurred to me that I could make it easier to compare our DataSets if I used XSLT to transform one of the XML files into a list.

Of the four files associated with the DataSet, I choose the XSS file because it is fairly simple and contains all the information I needed. The XSS file stores the position of the shapes on the design surface. I wanted to use the XSD file but I had a lot of trouble with it (more on that later).

It does not require any code to do a XML transformation in ASP.NET 2.0. Just drag an XML control onto your form and set the DocumentSource and the TransformSource:

<asp:Xml ID="Xml1" DocumentSource="~/App_Data/dsData.xss" runat="server" TransformSource="~/App_Data/XSS.xsl"></asp:Xml>

Although XSLT could be compared to CSS, being sort of a style sheet for XML, you can actually write a lot of code in your XSL files so you should regard it as a specialized programming language that you need to learn. Visual Studio 2005 does a good job as a XSLT editor but it is not perfect. It will alert you to syntax errors and malformed XML tags but lacks any Intellisense. The most frustrating aspect of coding XSLT is getting your XPaths correct. I usually have to experiment for hours before I can properly reference an XML element or attribute. The XML namespace often gives me a lot of trouble. This is why I could not use the XSD file. Its XML format makes getting a XPath extremely difficult and I was unable to reference the TableAdaper element. My XSL for the XSS file gives me a count of the TableAdapters in the DataSet and then lists them in alphabetical order as a numbered list. Getting the table count and sorting the TableAdapter names is done entirely in XSLT code which demonstrates the power of XML transformation:

<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet version="1.0" 
xmlns:ds="urn:schemas-microsoft-com:xml-msdatasource-layout" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" method="html" />
    <xsl:template match="/">
        <!-- This is an XSL template file. -->
        <table bgcolor="#FFFFFF" cellspacing="0" cellpadding="1">
            <tr bgcolor="#000000">
                <td>
                    <font color="#FFFFFF">
                        <b>
                            <!-- counter for xml elements -->
                            <xsl:value-of select="count(ds:DiagramLayout/ds:Shapes/ds:Shape)"/> Design Table(s)
                        </b>
                    </font>
                </td>
            </tr>
            <xsl:for-each select="ds:DiagramLayout/ds:Shapes/ds:Shape">
                <xsl:sort select="@ID"/>
                <xsl:if test="position() mod 2 = 1">
                    <tr bgcolor="#CCFFCC">
                        <td>
                            <xsl:number value="position()"/>.
                            <xsl:value-of select="substring-after(@ID,'DesignTable:')"/>
                        </td>
                    </tr>
                </xsl:if>
                <xsl:if test="position() mod 2 = 0">
                    <tr bgcolor="#FFFFFF">
                        <td>
                            <xsl:number value="position()"/>.
                            <xsl:value-of select="substring-after(@ID,'DesignTable:')"/>
                        </td>
                    </tr>
                </xsl:if>
            </xsl:for-each>
        </table>
    </xsl:template>
</xsl:stylesheet> 

The element count is accomplished by using the count function which requires the xpath to the element to be counted. The sorting of the XML elements is done by the XSL element xsl:sort which is selecting the ID attribute for each Shape element. I remove some text from the ID attribute using the substring-after function. The position function is used to number the elements and to alternate the HTML table row background color. The ds: prefix is required in the xpaths as a shorthand reference to the namespace and must be defined in the xsl:stylesheet element. This can be very tricky. It is usually very hard to get that right. XMLSpy can help you with that but it is very expensive.

By the way, while researching this, the XSS keyword gave me search results for Cross Site Scripting attacks using XSL. It is possible to extend the power of XSLT using JavaScript embedded into the XSL file. Therefore any web application that allows the user to upload their own XSL file will be vulnerable to Cross Site Scripting attacks. I've been learning a lot about the dangers of JavaScript snuck into user input. Attackers can use JavaScript in CSS files and send HTTP headers containing JavaScript for sneaky exploits but that is another topic.

First, let me introduce myself. I am a web developer and I've been using ASP.NET since 2001. I've only started to learn ASP.NET 2.0 and only started using Visual Studio 2005 this year. I am currently converting an ASP web application to ASP.NET 2.0. I have extensive technology notes which I maintain in a custom help collection integrated in the Microsoft Document Explorer. I've never worked with any other developers so nobody has ever benefited from my experience or seen my notes. I hope to share some of this material here.

 Eiffel is a programming language with some interesting features like design by contract which I won't attempt to describe. Eiffel software provides a CodeDom Provider for writing ASP.NET pages in Eiffel which is available for download for free on the Eiffel Software web site. There is very little sample code to be found on the Internet for using Eiffel with ASP.NET so I will share my sample code for a SQL Server database connection:

 

<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<html>
<head>
<title>Eiffel - SQL Server Database Connection</title>
<script runat="server">
   indexing
      description: "Connects to a SQL Server database using Eiffel for ASP.NET"
</script>
<script runat="server">
   inherit
      WEB_PAGE
         redefine
            on_load
         end
</script>
<script language="Eiffel" runat=server>
         on_load (e: EVENT_ARGS) is
               -- Initialize values
            local
               connection: DATA_SQL_CONNECTION
               command: DATA_SQL_COMMAND
               reader: DATA_SQL_DATA_READER
               ok: BOOLEAN
               data_string: STRING
            do
               if not is_post_back then
                  create data_string.make(1)
                  create connection.make ("server=SERVER_NAME;uid=***;pwd=***;database=Books")
                  create command.make("SELECT * FROM Books WHERE Author = 'Anne Rice'",connection)
                  connection.open
                  reader := command.execute_reader
                  
                  -- Iterate through result-set
                  from
                     ok := reader.read
                  until
                     not ok
                  loop
                     data_string.append(reader.item ("BookNum").to_string + " <u>" + reader.item ("Title").to_string + "</u> " + reader.item ("Author").to_string + "<br>")
                     ok := reader.read
                  end
                  ltlData.set_text (data_string)
   
                  -- Close everything
                  reader.close
                  connection.close
               end
            end
</script>
</head>
<body bgcolor="#FFFFFF">
<h1 style="font-family:Arial;">Eiffel - SQL Server Database Connection</h1>
<hr>
<font face="Arial">
<form runat=server>
   <asp:literal id="ltlData" runat="server" />
</form>
</font>
</body>
</html>
<!--
--+--------------------------------------------------------------------
--| Eiffel for ASP.NET 5.6
--| Copyright (c) 2005-2006 Robert S. Robbins
--|
--| Robert S. Robbins
--| http://www.williamsportwebdeveloper.com/
--+--------------------------------------------------------------------
-->

 

More Posts