Building a Telephony Application

 < Day Day Up > 

Designing a User Navigation Path

Before jumping in and writing code for a voice-only application, it is a good idea to determine the exact user navigation paths. Microsoft Visio was used to design the navigation flow for this chapter, but any tool that allows you to graphically design program functionality would work fine.

The Slugger Sports application allows the salesperson to retrieve two crucial types of information: new opportunities and product information. For telephony applications, the user is guided through the application with a series of questions and answers; therefore it is important to design simple and intuitive navigation.

Figure 3.3 illustrates the possible paths a salesperson can take. After being welcomed to the system, the salesperson will be prompted to say a first and last name. The application will then repeat the name it recognized and ask if it is correct. If the response is yes, the salesperson will be asked to enter a password code.

Figure 3.3. User flow for the voice-only sample application. By determining the navigation path before code is written, you can reduce the need for rewrites and determine what prompts are needed. Each shaded box represents an opportunity to both prompt a user and receive a response.


For the sample application, users are asked to say their first and last names in order to identify themselves. Since Slugger Sports is a small company with a limited number of salespeople, this is a viable method. For large companies that support hundreds or thousands of employees, it may be more practical to ask the user to say a unique identifier, such as an employee number.

The password code can be entered via the keypad or spoken as text. Allowing the user to enter via the keypad prevents anyone from overhearing the password code if it is spoken in a public area.

If the password code entered exists in the database, the salesperson is directed to the main menu. The salesperson is then asked what function they wish to perform. The system will list the possible functions and ask the user to respond with a

  • '1' for Get Product Info

  • '2' for Get Opportunities


Asking the salesperson to specify numbers instead of complete commands reduces the chance of error. However, utilizing numbered responses instead of voice commands makes the application less natural. This is a tradeoff to consider when designing a voice-only application.

A salesperson who wishes to get product info is asked for a product name. If the product name is found in the database, all current product information is listed. This information includes the number of units in stock, number of units on order, and unit price.

A salesperson who wishes to get new opportunities is first asked whether he or she has moved to a new area. Unexpected events can sometimes cause this to happen. If the salesperson is in the same area, the system looks for all leads in that area with a status of 'N'.

All functions end with a listing recited to the salesperson. To navigate through this listing, the salesperson can use the commands Next, Previous, and Read.

Determining the flow before the code is written can help reduce the need for code rewrites. Documented flows, even if handwritten, can also help to determine what recorded prompts are needed. This can be especially helpful when designing the prompt database.

Loading the Sample Application

Table 3.1 contains a listing of the two project files that comprise the sample application. To execute the sample code provided on the book's Web site, you will need to execute the following steps:


If IIS has already been installed on the machine, then by default you will have a directory named C:\Inetpub\wwwroot. Create a new folder in this directory named Chapter3 and copy the contents of the code directory for Chapter 3 (located on the book's Web site) to this location.


You will then need to open the Internet Information Services Manager and browse to the Default Web Site node. Right-click the newly created Chapter3 folder and click Properties. From the Directory tab, click the Create button. When finished, click OK and exit Internet Information Services Manager.


To enable dynamic grammars (discussed later in this section), you will need to grant the ASPNET account file access permissions to the grammars subdirectory. This is done using Microsoft Windows Explorer. Start by locating the grammar subdirectory (which should be located at C:\Inetpub\wwwroot\Chapter3\grammars), right-clicking the subdirectory, and clicking Properties. From the Security Tab, click the Add button. Enter the ASPNET account name and click OK to return. Select the Modify checkbox to allow the ASPNET account to write to the files located in this subdirectory.


As long as Visual Studio .NET has already been installed on your machine, you can open the code sample by double-clicking the solution file named Chapter3.sln from the C:\Inetpub\wwwroot\Chapter3 directory using Microsoft Windows Explorer.


After opening the solution file, you will need to set the start page. This is done by right-clicking the start page, Login.aspx, from Solution Explorer and clicking Set as Start Page.

Table 3.1. Code Listing for Chapter3 and SalesPrompts, the two projects that represent the sample application for this chapter. The files can be accessed by opening the Chapter3.sln file.


File Name




Solution file


Components/Dynamic Grammar.vb

Contains server-side Visual Basic code used to build all dynamic grammars.



Contains server-side Visual Basic code used by the Login.aspx page.



Contains server-side Visual Basic code used by the GetOpportunities .aspx page.



Contains server-side Visual Basic code used by the ProductList.aspx page.


Contains all the grammar files used in the sample application. The files are grouped into subdirectories.



User control that contains commonly accessed speech controls. This file is included on most pages.



JScript file that contains commonly accessed client-side JScript functions used in most pages.



Web page called when the user decides to exit the program. Contains a QA control that will thank the user for calling and then disconnect.



Web page called when an exception is encountered. Contains a QA control that will play once and inform the user that an error has occurred. It will then disconnect the user.



Web page used to retrieve a list of opportunities for a specific salesperson.



Web page used to request information for a specific product. The user will be redirected to the ProductList.aspx page after speaking the product name.

Prompt file that contains client-side Jscript code used by the GetProductInfo.aspx page.



Start page used to login to the system

Prompt file that contains client-side Jscript code used by the Login.aspx page.



Web page used to navigate to GetOpportinities.aspx or GetProductInfo.aspx

Prompt file that contains client-side Jscript code used by the MainMenu.aspx page.


XML-based file that contains a listing of resources that can be preloaded by Speech Server.



Web page used to select a product from a list and then redirect to the GetProductInfo.aspx page.

Prompt file that contains client-side Jscript code used by the ProductList.aspx page.



JScript file that contains commonly accessed client-side JScript functions used in most pages to generate prompts.



Prompt Database file used to hold all recorded prompts used by the Chapter3 project.

Examining the Startup Web Page

The startup page for the sample application is Login.aspx. This page will handle the initial validation of the salesperson by asking for a user name and password code. Validation is accomplished by executing server-side code and calling the VerifyPasscode function. VerifyPasscode, found in the Login.vb code file, executes the VerifyLogin SQL Server stored procedure. Once validated, the user will be redirected to the MainMenu.aspx page.

The first control associated with Login.aspx (see Figure 3.4) is a user control that references the Common.ascx file. This control groups together the common navigational commands Help, Repeat, and Main Menu. The commands are placed in a user control so they can be reused in other pages. This group also contains Include statements that point to JScript files containing commonly used client-side functions.

Figure 3.4. Partial Screenshot of the Design view for Login.aspx (the startup Web page). Since the sample application is voice-only, no visible controls are needed.

The second control on the page is the SemanticMap. This control contains information about all the semantic items used on the page. Normally there will be one semantic item associated with each piece of information retrieved from the user. For the login page, there will be two: siUserName and siPasscode. Semantic items can be viewed and edited by selecting the control and clicking the Property Builder link inside of Properties.

The first control that initiates an interaction with the user is the AnswerCall control. The next control, named WelcomeQA, is used to read a welcome message one time. This control is the only one that utilizes an Inline prompt. All the other controls will utilize prompt functions. Although you have the option of using an Inline prompt for all controls, it is recommended that you not do so. Inline prompting involves hard-coding the prompt used for the control. It is inflexible and can present a maintenance problem in your application.

Using Prompt Functions

A voice-only application will typically contain several prompt functions. Prompt functions represent client-side Jscript code that is used to generate dynamic prompts depending on the flow of dialog.

For our sample application, the control that begins the first dialog with the user is AskUserNameQA. To view the prompt associated with this control, click on the PropertyBuilder link at the bottom of the Properties box. Click the General tab under Voice Output. From here, you will see that the control uses a prompt function named AskUserNameQA_prompt (see Figure 3.5). You can go directly to the code for this function by clicking Edit prompt function file. You can also access the function by double-clicking the file from Solution Explorer.

Figure 3.5. Screenshot of the Property Builder dialog as it displays properties for the AskUserNameQA control. This control uses a prompt function named AskUserNameQA_Prompt.


By default, the SASDK creates a prompt function file (with a .pf extension) with the same name as the Web page. This is done the first time the developer clicks <New. . .> from the Prompt Options dialog (see Figure 3.5).

To prevent code redundancy, the application utilizes a file named PromptGenerator.js. This javascript class includes code used by all QA controls to generate prompts. Utilizing the Generate function makes it unnecessary to include code for handling commands such as Help and Repeat within each prompt function.

 function PromptGenerator.Generate(History, text, help) {    switch (History[History.length - 1])    {     case "NoReco":      if (History.length > 1)        return "Sorry, I still don't understand you. " + help;      else        return "Sorry, I am having trouble understanding you. If you          need help, say help. " + text;    case "Silence":      if (History.length > 1)        return "Sorry, I still don't hear you. " + help;      else        return "Sorry, I am having trouble hearing you. If you need          help, say help. " + text;     case "Help":        PromptGenerator.RepeatPrompt = help;        return help;     case "Repeat":        return "I repeat: " + PromptGenerator.RepeatPrompt;     default:        PromptGenerator.RepeatPrompt = text;        return text;  } } 

The function accepts three parameters: history, text, and help. These parameters allow you to control what prompts are displayed depending on the user's response. A user who does not respond before the InitialTimeout property expires will be prompted with "Sorry, I am having trouble hearing you. If you need help, say help." For subsequent silence periods, it will respond with "Sorry, I still don't hear you" along with the help string from the calling prompt function.

Prompt functions allow you to vary what is prompted to the user depending on the situation. This helps to create a more dynamic and natural-sounding dialog. Instead of hearing the same phrase repeated endlessly, the user will get different prompts.

Building a Dynamic Grammar

The QA control represents a specific interaction with the user. This includes not only the prompt but the grammar as well. The grammar associated with the AskUserNameQA control is username.grxml. This is seen by viewing the Grammar tab in Property Builder. Since the user name is the name of the employee, and employee turnover at Slugger Sports is high, this grammar is created dynamically. The username.grxml file is rewritten every time the login page is loaded.

Since dynamic grammars will be utilized more than once in this application, a central function named LoadGrammarFile was placed in the DynamicGrammars class file (available within the Components folder of Solution Explorer).

LoadGrammarFile accepts three parameters: the file location, the node name to be used in the grammar file, and the SQL Server stored procedure name used to access the data from the SalesScheduling database. By utilizing a central function, we do not have to repeat identical code throughout the application. Dynamic grammars will be used when requesting the user names and product names.

The following code snippet shows the contents of the LoadGrammarFile method. This method accepts as parameters the file location, the name to be shown in the SML, and the stored procedure used to access the data.

 Public Shared Sub LoadGrammarFile(ByVal fileloc As String, _            ByVal Name As String, ByVal sp As String) 'Define location for resulting grammar file Dim xmlFileOutputLoc As String = fileloc Dim sb As New StringBuilder 'Define the high level tags used in the grammar file sb.Append( _   "<grammar xml:lang=""en-US"" tag-format=""semantics-ms/1.0"" " _   & "version=""1.0"" root=""" + Name + "Rule"" mode=""voice"" " _   & "xmlns="""">") sb.Append("<rule " + Name + "Rule"" scope=""public"">") 'Define one-of elements which indicates a list sb.Append("<one-of>") Dim dr As SqlDataReader = SqlHelper.ExecuteReader( _    ConfigurationSettings.AppSettings("Chapter3.Connection"), _    CommandType.StoredProcedure, sp) 'Loop through the Datareader Do While dr.Read() sb.Append(DynamicGrammar.ConvertGrammarItem(Name, _    dr.GetString(0))) Loop 'Closing tags sb.Append("</one-of>") sb.Append("</rule>") sb.Append("</grammar>") 'Write out the new file Dim xDoc As XmlDocument = New XmlDocument xDoc.LoadXml(sb.ToString) xDoc.Save(xmlFileOutputLoc) End Sub 

This function builds an XML stream needed for the grammar file. It then calls the ExecuteReader function of the SqlHelper class to execute the stored procedure name passed in as a parameter. Once all the grammar items are loaded into the stream, it writes the output to disk.


In order for the function to write the XML file, you will have to grant the ASPNET account write access to the file located at Server.MapPath(Request.ApplicationPath + "/Grammars/UserNames.grxml"). The exact file location depends on where the Chapter3 application is installed on your Web server.

The username.grxml file is necessary in order for the speech engine to recognize the employee's name. Every time the speech engine processes input from the user, it returns an SML stream that indicates what was recognized. The SML contains the text interpreted by the speech engine along with a confidence score (a score of 1.0 indicates a 100 percent confidence). Controls can be configured to only accept results above a certain confidence score. I would recommend setting an initial confidence score of .70 and then adjusting it if necessary.

LoadGrammarFile also calls a function named ConvertDataItem, seen as follows, which is used to format the record values as XML.

 Public Shared Function ConvertGrammarItem(ByVal Name As String, _      ByVal GrammarItem As String) As String            ' Build the grxml <item> element      Dim s As New StringBuilder            s.Append("<item>")      s.Append("<item>")      s.Append(GrammarItem)      s.Append("</item>")      s.Append("<tag>$." + Name + " = """ + _         GrammarItem + """</tag>")      s.Append("</item>")            Return s.ToString() End Function 

Other Page Controls

The sample application in this chapter utilizes a user control named common.ascx. This control is placed on every page and contains Include statements pointing to common files such as PromptGenerator.js. It also contains QA controls for our global commands Help and Repeat. Otherwise, we would have to duplicate these controls on every page. Finally, it contains a SpeechControlSettings control used to define common properties for certain types of controls.

The Semantic Map control defined the semantic item associated with the user name. The value spoken by the user is stored in a session variable named UserName and can be referenced in other areas of the code. The AskUserNameConfirm QA control is used to repeat the user name to the user and ask if the value is correct. Since it is possible for the speech engine to recognize the user name incorrectly, this allows the user to start over if necessary.

The confirmation control utilizes a grammar named YesNo.grxml and is an example of using the RuleRef control (see Figure 3.6). The root node for this grammar file contains references to two other rules: Yes and No. By using rule references, complex grammars can be broken down into more manageable units and then assembled into one root rule (the root rule is the one loaded by default). The rule can be referred to with the pound sign and rule name after the grammar file name. For example, the src property for the grammar tag would contain the value Grammars/Common/YesNo.grxml#YesNoRule.

Figure 3.6. Partial screenshot of the Grammar Editor as it displays the YesNoRule. This rule utilizes a RuleRef control to reference the Yes and No rules. The rule name is preceded with a pound sign.

The final control on the Login page is the PasscodeQA. This control is responsible for prompting the user for the password code and then recognizing the digits entered on the phone keypad. DTMF stands for Dual Tone Multi-Frequency tones, and it represents tones resulting from pressing a keypad. The PasscodeQA control references both the Passcode.grxml and PasscodeSpoken.grxml files. The Passcode.grxml file is of mode DTMF. This is specified in the Mode property for the QA control. The PasscodeSpoken.grxml file is used for spoken digits, such as "one" or "two." The application allows the user the choice of speaking the password code or keying it in via the phone pad. This helps to ensure the security of the password code when the user is in a public area.

The root rule PasscodeRule (see Figure 3.7) for both grammars references a rule named digit. Since a passcode should be exactly six digits long, we will set the Max Repeat and Min Repeat properties with a value of 6. Once six digits are entered, the speech engine interprets the result and writes out the SML.

Figure 3.7. Screenshot of the Grammar Editor as it displays part of the PasscodeRule. This is the root rule used to evaluate the user's spoken passcode. The rule will collect six digits since the Max Repeat and Min Repeat properties are both set with a value of 6.

Posting Back to the Server

Once the last control is evaluated, a postback to the server will occur automatically, and code in the page_load (as follows) will call the VerifyPasscode function.

 Dim _DynamicGrammar As CDynamicGrammar Dim _Login As CLogin Try   If Page.IsPostBack Then     If siPasscode.Text <> "" Then       Dim apasscode As String() = siPasscode.Text.Split(" ")       Dim spasscode As String = ConvertNumtoDigits(apasscode)       Dim ipasscode As Integer = Convert.ToInt32(spasscode)       _Login = New CLogin       If _Login.VerifyPasscode(ipasscode, siUserName.Text) Then         'Save this for later         Session("UserName") = siUserName.Text         Server.Transfer("MainMenu.aspx")       Else         'Reset the state b/c we are going to         'prompt the user for the passcode again         siPasscode.State = "Empty"       End If     End If   Else     Dim strPath As String = _     Server.MapPath(Request.ApplicationPath _       + "/Grammars/Login/UserNames.grxml")       _DynamicGrammar.LoadGrammarFile(strPath, _       "UserName", "GetUserNames")   End If Catch ex As Exception   ExceptionManager.Publish(ex)   Server.Transfer("Error.aspx") Finally   _Login = Nothing   _DynamicGrammar = Nothing End Try 

The VerifyPasscode function accepts the values stored in the semantic items siUserName and siPasscode. It then executes the VerifyLogin stored procedure to determine whether the user name matches the password code in the database. If it does, the user is redirected to the MainMenu.aspx page.

If an error is encountered, the error handler will log the exception to the server's application event log. The application will then redirect the user to the Error.aspx page. The Error.aspx page contains a QA control and a DisconnectCall control. The QA control is responsible for informing the user that an error has occurred and it is necessary to contact the Main Office for further assistance. The message will play only once and then the user will be disconnected by the DisconnectCall control.


This chapter utilizes the Exception Management Application block available from the Microsoft Patterns and Practices Group. By default, the exception manager will log all exceptions to the server's application event log.

Readers interested in learning more about the different options available for exception handling should refer to the Microsoft Web site at

Vocal Help Desk

Solar Software (, located in Columbus, Ohio, was the first Microsoft Speech partner to demonstrate a working application. Powered by Microsoft Speech Server, Vocal Help Desk 1.0 allows users to access the Vocal Help Desk application by phone and reset their network passwords.

Automating and speech-enabling this frequently required task not only frees up valuable time for network administrators, but it gets users back to work quicker. Solar Software estimates that the application can reduce calls to the IT help desk by as much as 30 percent.

Network administrators can also use Vocal Help Desk to reboot servers, restart services, and disable accounts.

Vocal Help Desk is just one example of how functionality exposed through the Active Directory can be speech-enabled.

The Main Menu

The MainMenu.aspx page is used to determine what function the user wishes to perform and then direct the user to the appropriate page. Only one QA control is needed for the MainMenu.aspx page. It contains a reference to the Common user control and a Semantic Map control. The semantic map holds one item: siMainFunction. The QA control for the page is named MainMenuQA, and the prompt function it uses is MainMenuQA_prompt.

The Function to Get Product Info

Function 1, Get Product Info, allows the user to say a product name and retrieve information about the product. The information that can be retrieved includes the number of items in stock, the number of items on order, and the unit price. This allows the salesperson to quickly reference the latest product information while at a customer's location.

Ordering Speech Controls

Speech controls are activated according to their order on the Web page. Another alternative is to assign a value to the SpeechIndex property for the QA control. This allows you to specify an order different from the physical order. The GetProductInfo.aspx page demonstrates the use of the SpeechIndex property. The ProductNameConfirm control physically resides on this page before the ProductNameQA control and by default would be activated first. The activation order for this page can be viewed by going to View and Speech Controls Outline (see Figure 3.8). Because the SpeechIndex property was utilized, the order indicates that the ProductNameQA control will be activated first instead.

Figure 3.8. Screenshot of the Speech Controls Outline dialog box. This allows you to alter the order in which controls on a page will be evaluated.

Retrieving the Product Information

The GetProductInfo.aspx page is similar to the Login.aspx page in that it uses a dynamic grammar. This is used to get product names that are not discontinued. Once the product name is confirmed, the user is directed to the ProductList.aspx page. The ProductList.aspx page loads with a call to the GetProductList stored procedure, which is used to retrieve product information from the SalesScheduling database. The data values returned from the stored procedure call are then appended, as follows, into a string that is returned from the GetProductList function.

'Set and value input parms Dim params(0) As SqlParameter params(0) = New SqlParameter("@prodname", SqlDbType.VarChar, 50) params(0).Value = prodname 'Use the parameters in a command Dim dr As SqlDataReader dr = SqlHelper.ExecuteReader(AppSettings("Chapter3.Connection"), _  CommandType.StoredProcedure, MethodInfo.GetCurrentMethod.Name, params) Dim sb As New StringBuilder Do While dr.Read    sb.Append("Product " + prodname + " consists of ")    sb.Append(Convert.ToString(dr("numitems")) + " items, has ")    sb.Append(Convert.ToString(dr("unitsinstock")) + " items in stock, ")    sb.Append(Convert.ToString(dr("unitsonorder")))    sb.Append(" items on order and lists for ")    sb.Append(Convert.ToString(dr("unitprice"))) Loop Return sb.ToString 

The string returned from the GetProductList function will be used to assign a value to a semantic item used in the prompt function for the ProductInfoReview QA control. Finally, the user is asked whether they want to get another product. If the answer is yes, the user is redirected to the GetProductInfo page. Otherwise, the user is redirected to the MainMenu page.

The Function to Get Opportunities

Another main menu option is get opportunities. By selecting this option, the salesperson is redirected to the GetOpportunities.aspx page. The first question asks whether the salesperson's area code has changed. If the reply is a yes, the salesperson is asked for the new area code. Otherwise, the GetOpportunityList stored procedure is used to return a dataset containing opportunities for the current day. The data returned from the stored procedure call is then formatted and returned in a new dataset. It is this dataset that is used to populate a DataTableNavigator application control.

The DataTableNavigator control has built-in functionality that allows the user to navigate several rows of data. Navigation commands such as "Next" and "Read" are specified through control properties. This control greatly simplifies the process of reviewing data.

For the GetOpportunityList function, the content results are formatted as one string which is then returned as a field in a dataset (as follows).

 'Split the name into a first and last name Dim uname As String() = username.Split(" ") Dim firstname As String = uname(0).ToString Dim lastname As String = uname(1).ToString 'Set and value input parms Dim params(1) As SqlParameter params(0) = New SqlParameter("@firstname", SqlDbType.VarChar, 30) params(1) = New SqlParameter("@lastname", SqlDbType.VarChar, 30) params(0).Value = firstname params(1).Value = lastname 'Use the parameters in a command Dim dr As SqlDataReader dr = SqlHelper.ExecuteReader(AppSettings("Chapter3.Connection"), _  CommandType.StoredProcedure, MethodInfo.GetCurrentMethod.Name, params) 'Define a Data table used to hold the formatted results Dim dTable As New DataTable Dim colCompany As DataColumn = New DataColumn("company", _   System.Type.GetType("System.String")) dTable.Columns.Add(colCompany) Dim colOppString As DataColumn = New DataColumn("oppstring", _   System.Type.GetType("System.String")) dTable.Columns.Add(colOppString) Dim rowTable As DataRow Do While dr.Read   rowTable = dTable.NewRow   rowTable("company") = Convert.ToString(dr("company"))   Dim strDesc As String   If dr("appointment") = 1 Then     strDesc = "Appointment starts at " + _          Convert.ToString(dr("starttime"))   Else     strDesc = "Opportunity starts at " + _          Convert.ToString(dr("starttime"))   End If   strDesc = strDesc + " and ends at " + Convert.ToString(dr("endtime"))   strDesc = strDesc + " notes are " + Convert.ToString(dr("notes"))   strDesc = strDesc + " and it was referred by "   strDesc = strDesc + Convert.ToString(dr("referredby"))   rowTable("oppstring") = strDesc   dTable.Rows.Add(rowTable) Loop Dim ds As New DataSet ds.Tables.Add(dTable) dr = Nothing dTable = Nothing colCompany = Nothing colOppString = Nothing Return ds 

Voice Manager Exchange, 3.0

HeyAnita Inc ( is a Microsoft Speech partner based out of Los Angeles. It provides messaging solutions to telecommunication operators like Verizon Wireless and Sprint PCS.

Voice Manager Exchange is one of the products it offers as part of the Voice Manager Suite. This application allows remote users to access their Microsoft Exchange e-mails, calendars, and contacts through a phone.

This is a great way for mobile workers to get hands-free access to vital contact information while they are literally "on the road." Once a contact is located by voice, the mobile worker can dial it by just saying his or her name.

In the case study involving GMAC Commercial Mortgage, the company's IT staff built a customized speech application to give remote executives voice access to their e-mails. For companies not able or willing to develop their own solution, Voice Manager Exchange may be a better alternative to getting voice access to e-mail.

Navigating the Application

At any point after login, the salesperson has the option of returning to the main menu page by saying "Main Menu" or ending the call by saying "Disconnect." These commands are available through the common.ascx file.

The Common user control contains four global commands that can be called from any page: Help, Repeat, Main Menu, and Disconnect. All four controls are contained within a panel Web control to identify their scope. Since the Speech Engine will read the grammars for these controls every time a page is activated, you want to limit the number of global commands.

The MainMenuCmd and DisconnectCmd are different from the other global commands because they execute a triggered event when activated. The triggered events call server routines that redirect to either MainMenu.aspx or Disconnect.aspx.

 Private Sub DisconnectCmd_Triggered(ByVal sender As System.Object, _    ByVal e As Microsoft.Speech.Web.UI.CommandTriggeredEventArgs) _    Handles DisconnectCmd.Triggered         Server.Transfer("Disconnect.aspx") End Sub Private Sub MainMenuCmd_Triggered(ByVal sender As System.Object, _    ByVal e As Microsoft.Speech.Web.UI.CommandTriggeredEventArgs) _    Handles MainMenuCmd.Triggered           If Session("UserName") <> "" Then         Server.Transfer("MainMenu.aspx")      End If End Sub 

The triggered event for the Main Menu command ascertains whether the public variable that stores the user name contains a value. If the variable contains a blank value, then we know the user has not been validated and thus should not be directed to the main menu page. The session variable UserName is set in the code of Login.aspx only after the user has been successfully validated.

     < Day Day Up > 

    Building Intelligent  .NET Applications(c) Agents, Data Mining, Rule-Based Systems, and Speech Processing
    Building Intelligent .NET Applications(c) Agents, Data Mining, Rule-Based Systems, and Speech Processing
    ISBN: N/A
    EAN: N/A
    Year: 2005
    Pages: 123 © 2008-2017.
    If you may any questions please contact us: