Developing with Visual C .NET


Developing with Visual C# .NET

Visual C# .NET is a new language that made its appearance as part of Visual Studio .NET. The language combines the flexibility of C++ with some of the programmer productivity benefits of using Visual Basic. In addition, it bears a striking resemblance to Java in many ways. In fact, many developers say that C# is Microsoft's attempt to create something as useful as Java.

No matter how you feel about C#, it's a capable language that lets you perform some tasks that Visual Basic .NET doesn't. For example, Visual Basic doesn't let you create unsafe code ”that is, code that contains unmanaged pointers. C# lets you create such code so that you can perform some low-level tasks that Visual Basic isn't designed to perform. From a Google Web Services perspective, the two languages are probably equivalent and the choice of language comes down to coding style. However, it's important to keep the differences between Visual Basic and C# in mind if you plan to create a complex application. The following sections show how to create a basic C# Google Web Services application.

Using the Google C# Example

The Google Web Services Kit comes with an example application written in C#. You'll find it in the \GoogleAPI\dotnet\CSharp folder. The example demonstrates how to use Google Web Services, but doesn't do much with the data. This application is essentially the same as the Visual Basic version of the application. See the "Using the Google Visual Basic .NET Example" section of the chapter for additional information.

Defining a Search with Visual C# .NET

Creating a search with Visual C# is about the same as working with Visual Basic. The two languages do have differences though, so you need to exercise care in assuming they're interchangeable. Listing 6.5 shows a typical search application written in Visual C#. You'll find the complete source for this example in the \ Chapter 06 \ C_SharpSearch folder of the source code located on the Sybex Web site.

Listing 6.5: Creating a Search with Google
start example
 private void btnTest_Click(object sender, System.EventArgs e)   {      GoogleSearchService Service; // Search service routine access.      GoogleSearchResult Result;   // All of the results.      ResultElement[] Items;       // All of the search items.      DataRow DR;                  // Output data.      // Create the search service.      Service = new GoogleSearchService();      // Make the call.      Result = Service.doGoogleSearch(txtLicense.Text, txtKey.Text,                                      Convert.ToInt32(txtIndex.Text),                                      Convert.ToInt32(txtResults.Text),                                      cbFiltering.Checked,                                      txtCountry.Text,                                      cbSafeSearch.Checked,                                      txtLanguage.Text,                                      "", "");      // Process the main nodes.      txtIndex.Text = Convert.ToString(Result.endIndex + 1);      txtEstResults.Text = Result.estimatedTotalResultsCount.ToString();      cbEstExact.Checked = Result.estimateIsExact;      // Clear the dataset of previous results.      dsGoogle.Tables["SearchResults"].Clear();      // Process the result elements.      Items = Result.resultElements;      foreach (ResultElement Item in Items)      {         // Add a row.         DR = dsGoogle.Tables["SearchResults"].NewRow();         // Add the data to the row.         DR["Title"] = StringToText(Item.title);         DR["URL"] = Item.URL;         if (Item.snippet.Length > 0)            DR["SnippetOrSummary"] = StringToText(Item.snippet);         else            DR["SnippetOrSummary"] = StringToText(Item.summary);         DR["CachedSize"] = Item.cachedSize;         // Display the row on screen.         dsGoogle.Tables["SearchResults"].Rows.Add(DR);      }   } 
end example
 

The code begins by creating a GoogleSearchService object. This object contains references to all of the Google Web Services functions. The code uses the Service.doGoogleSearch() method to create a GoogleSearchResult object that contains all of the search results.

As with Visual Basic, you can read the top-level nodes, such as estimateIsExact , directly using properties. The resultElements property requires loop processing using a foreach structure.

The example stores the individual rows in dsGoogle , a DataSet that is connected to the dgGoogle DataGrid . Changes in dsGoogle automatically appear on screen. The code begins by creating a new row in dsGoogle using the NewRow() method. The resulting DataRow object, DR, contains all of the columns in the table. The code adds individual data values to each column, and then adds the data into the table using the dsGoogle.Tables[ SearchResults ].Rows.Add() method. The results look similar to the Visual Basic .NET application output shown in Figure 6.11.

Using SQL Server as a Database

Using a cache to hold your Google search data is a good idea for a number of reasons. For example, using a cache helps you improve application performance. For more information on how to use caching, see the "Caching as a Practical Performance Enhancing Technique" section of Chapter 5. The example in this section relies on SQL Server to provide caching functionality. However, you could easily adapt the example to use any Database Management System (DBMS). In fact, you don't have to use a DBMS at all ”a simple XML file (or even a text file) works fine for personal needs.

The SQL database for this example contains two tables. The first stores the main node results, such as the estimated number of links for a particular search. The second stores the links the application retrieved for the search. The database links the two tables using an automatically incremented index. You'll find the SQL script and data for the example in the \ Chapter 06 \ SQL Data folder on the Sybex Web site.

The example concentrates on making searches as efficient as possible. However, you must also age the data found in the database to ensure you don't get bad results from your search. Consequently, the application checks the age of the data before it makes a request. Listing 6.6 shows how to perform multiple requests with data aging. You'll find the complete source for this example in the \ Chapter 06 \ SQL Storage folder of the source code located on the Sybex Web site.

Listing 6.6: Caching Google Web Services Data
start example
 private void btnTest_Click(object sender, System.EventArgs e)   {      SqlCommand Query;   // Asks for the search data.   SqlDataReader DatRead; // Contains search results.   Object[] Results;      // An array of result values.   DataRow DR;            // Output data.   DateTime Scan;         // The scan date.   String SrchNum;        // Search number field data.   // Clear the dataset of previous results.   dsGoogle.Tables["SearchResults"].Clear();   // Look for the requested search.   Query =      new SqlCommand("SELECT * FROM SearchQueries WHERE SearchQuery='"        + txtKey.Text + "';", connGoogleData);   // Open the database connection and make the query.   connGoogleData.Open();   DatRead =      Query.ExecuteReader(System.Data.CommandBehavior.SingleRow);   // If the data is available, read it into a result array.   if (DatRead.Read())   {      Results = new Object[DatRead.FieldCount];      DatRead.GetValues(Results);      // Make sure you close the database connection.      connGoogleData.Close();      // Verify the data isn't too old.      Scan = Convert.ToDateTime(Results[8].ToString());      if (Scan.AddHours(24) < DateTime.Now)      {         // Get the search number.         SrchNum = Results[0].ToString();         // Remove the old search record.         connGoogleData.Open();         Query =            new SqlCommand("DELETE FROM SearchQueries WHERE "              "SearchNumber='" + SrchNum + "'", connGoogleData);         Query.ExecuteNonQuery();         // Remove the old results records.         Query =            new SqlCommand("DELETE FROM Results WHERE SearchNumber='" +            SrchNum + "'", connGoogleData);         Query.ExecuteNonQuery();         connGoogleData.Close();         // If it is, then update the database.         Results = GetGoogleData();      }   }      else      {         // Close the database connection so we can add data.         connGoogleData.Close();         // Otherwise, request the data from Google.         Results = GetGoogleData();      }      // Process the main nodes.      txtScanDate.Text = Results[8].ToString();      ... Other Main Nodes ...      // Process the result nodes.      Query =         new SqlCommand("SELECT * FROM Results WHERE SearchNumber='" +            Results[0] + "'", connGoogleData);      // Open the database connection and make the query.      connGoogleData.Open();      DatRead = Query.ExecuteReader();      // Configure the array to hold the results data.      Results = new Object[DatRead.FieldCount];      // Process each of the result rows in turn.      while (DatRead.Read())      {         // Get the current data.         DatRead.GetValues(Results);         // Add a row.         DR = dsGoogle.Tables["SearchResults"].NewRow();         // Add the data to the row.         DR["Title"] = Results[1].ToString();         ... Other Rows ...         // Display the row on screen.         dsGoogle.Tables["SearchResults"].Rows.Add(DR);      }      // Close the connection when finished.      connGoogleData.Close();   } 
end example
 

The code begins by clearing the old data from the form. The dsGoogle DataSet is connected to the data grid on the form. The dsSQLStorage DataSet interacts with the database. The reason the application uses two DataSet objects is that one is typed (for the SQL database) and the other is untyped.

The next step is to open the database and search for the keyword string. In this case, the code creates a SqlCommand object, Query , and uses it to execute a SQL query. Notice that you must open the database connection before using it. The example uses two tables to store information ”the SearchQueries table contains the keywords used to create the search, while the Results table contains the individual page information (including title and URL).

When the query is successful, the DatRead.Read() method returns true. This method also fills the DatRead object with one row of data that you can process. The DatRead.Read() method continues to return true so long as there are rows to process. You can't read these values directly. The code uses the DatRead.GetValues() method to place the values in an Object array named Results.

It's possible, at this point, to check the scan date of the data. This step is where data aging comes into play. The Results[8] object contains the scanned date. The code places this information into Scan, adds 24 hours to the current value, and compares it to the current date. If the data is too old, then the code clears the information from the database and calls GetGoogleData() (discussed as part of Listing 6.7) to make a query to Google Web Services. Suppose for a moment that this is the first time the user has made a particular query. In this case, the code closes the database connection and calls GetGoogleData() immediately.

Note  

Make sure you use the Query.ExecuteNonQuery() method to delete records from the database. The Query.ExecuteReader() method returns a result and there isn't a result when you delete records. The Query.ExecuteNonQuery() method does return the number of records affected by the call, so you can verify the command worked as intended.

No matter how the code eventually satisfied the first step of obtaining the SearchQueries table data, the code can now display top-level information such as the total estimated number of records. The code displays this information on screen. Because the data is already clean of HTML tags and encoded characters , all the code needs to do is transfer the data from the Results array to the individual form controls.

It's time to get the result nodes ”the ones that have the title and URL information. This step should always succeed because the GetGoogleData() method always places the result information in the Results table. The code relies on Query again to store the SQL statement and execute it against the database. As with the SearchQueries table, the Results table query relies on a Query.ExecuteReader() method call to fill DatReader with information. The code reads each of the results in a loop and places them in dsGoogle, which also displays the data on screen.

No matter how you work with Google Web Services, you need to create a client and call one of the supported methods at some point. This aspect of working with Google Web Services won't change. However, what you do to prepare for the call and how you handle the data once you receive it will change. This application requires special handling because you need to get the data from Google Web Services to your database cache. Listing 6.7 shows one way to perform this task.

Listing 6.7: Getting the Google Data
start example
 private Object[] GetGoogleData()   {      GoogleSearchService Service; // Search service routine access.      GoogleSearchResult Result;   // All of the results.      ResultElement[] Items;       // All of the search items.      DataRow SrchStore;           // Row for Search storage.      DataRow ResStore;            // Row for Result storage.      Int32 SrchNum;               // SrchStore search number.      // Create the search service.      Service = new GoogleSearchService();      // Make the call.      Result = Service.doGoogleSearch(txtLicense.Text, txtKey.Text,                                      0, 10, cbFiltering.Checked,                                      txtCountry.Text,                                      cbSafeSearch.Checked,                                      txtLanguage.Text, "", "");      // Create the new search query record.      SrchStore = dsSQLStorage.Tables["SearchQueries"].NewRow();      // Insert the new data into the DataRow.      SrchStore["SearchQuery"] = txtKey.Text;      SrchStore["DocumentFiltering"] =         Result.documentFiltering;      ... Other Data Entries ...      SrchStore["DateScanned"] = DateTime.Now;      // Add the new search query record to the database.      dsSQLStorage.Tables["SearchQueries"].Rows.Add(SrchStore);      daSearchQueries.Update(dsSQLStorage, "SearchQueries");      // Save the new search number.      SrchNum = Convert.ToInt32(SrchStore["SearchNumber"]);      // Process the result elements.      Items = Result.resultElements;      foreach (ResultElement Item in Items)      {         // Create the new results record.         ResStore = dsSQLStorage.Tables["Results"].NewRow();         // Add the data to the row.         ResStore["SearchNumber"] = SrchNum;         ResStore["Title"] = StringToText(Item.title);         ... Other Data Entries ...         ResStore["CachedSize"] = Item.cachedSize;         // Add the new results record to the dataset.         dsSQLStorage.Tables["Results"].Rows.Add(ResStore);      }      // Update the database with all the new results records.      daResults.Update(dsSQLStorage, "Results");      // Return the search query results.      return SrchStore.ItemArray;   } 
end example
 

The code begins by creating a client and calling the doGoogleSearch() as discussed in other examples in this chapter. The example begins with the first result and obtains 10 results from Google. You can add the capability of retrieving the entire result set or some portion of it (as shown in the other examples in this chapter). The reason I limited the result set was to focus on the caching portion of the application.

Unlike other examples in this chapter, this example doesn't immediately display the data on screen. Instead, it begins by placing the top-level data in the SearchQueries table. The code adds a row using the NewRow() method, fills the resulting DataRow with information, and updates the table using the daSearchQueries.Update() method.

Warning  

You must update the SearchQueries table before you proceed to the Results table. The SrchStore[ SearchNumber ] property doesn't receive the correct value until after the update. Consequently , if you don't perform the update, the code will always add new results to SearchNumber 0 , not the current SearchNumber value .

Processing of the Result.resultElements property works much as it does for the other examples. The difference, in this case, is that the data is placed in dsSQLStorage and eventually moved to the database. Notice that the code adds all of the data rows before it calls the daResults.Update() method. This technique ensures you get optimal performance from the application. Figure 6.12 shows typical output from this application.

click to expand
Figure 6.12: Output from the caching application demonstrates that a local cache is faster than calling Google Web Services.



Mining Google Web Services
Mining Google Web Services: Building Applications with the Google API
ISBN: 0782143334
EAN: 2147483647
Year: 2004
Pages: 157

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net