Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Visual CSharp 2005 Recipes (2006) [eng]

.pdf
Скачиваний:
49
Добавлен:
16.08.2013
Размер:
4.04 Mб
Скачать

328 C H A P T E R 9 D ATA B A S E A C C E S S

Solution

Program to the ADO.NET data provider interfaces in the System.Data namespace, as opposed to the concrete implementations, and do not rely on features and data types that are unique to specific database implementations. Use factory classes and methods to instantiate the data provider objects you need to use.

How It Works

Using a specific data provider implementation (the SQL Server data provider, for example) simplifies your code and may be appropriate if you need to support only a single type of database or require access to specific features provided by that data provider, such as the asynchronous execution for SQL Server detailed in recipe 9-9. However, if you program your application against a specific data provider implementation, you will need to rewrite and test those sections of your code if you want to use a different data provider at some point in the future.

Table 9-6 contains a summary of the main interfaces you must program against when writing generic ADO.NET code that will work with any relational database’s data provider. The table also explains how to create objects of the appropriate type that implement the interface. Many of the recipes in this chapter demonstrate the use of ADO.NET data provider interfaces over specific implementation, as highlighted in the table.

Table 9-6. Data Provider Interfaces

Interface

Description

Demonstrated In

IDbConnection

Represents a connection to a relational database.

Recipe 9-1

 

You must program the logic to create a connection

 

 

object of the appropriate type based on your

 

 

applications configuration information, or use the

 

 

DbProviderFactory.CreateConnection factory

 

 

method (discussed in this recipe).

 

IDbCommand

Represents a SQL command that is issued to

Recipe 9-5

 

a relational database. You can create IDbCommand

 

 

objects of the appropriate type using the

 

 

IDbConnection.CreateCommand or

 

 

DbProviderFactory.CreateCommand factory method.

 

IDataParameter

Represents a parameter to an IDbCommand object.

Recipe 9-6

 

You can create IDataParameter objects of the

 

 

correct type using the IDbCommand.CreateParameter,

 

 

IDbCommand.Parameters.Add, or DbProviderFactory.

 

 

CreateParameter factory method.

 

IDataReader

Represents the result set of a database query and

Recipes 9-5 and 9-6

 

provides access to the contained rows and columns.

 

 

An object of the correct type will be returned when

 

 

you call the IDbCommand.ExecuteReader method.

 

IDbDataAdapter

Represents the set of commands used to fill

 

 

a System.Data.DataSet from a relational database

 

 

and to update the database based on changes to

 

 

the DataSet. You must program the logic to create

 

 

a data adapter object of the appropriate type based

 

 

on your applications configuration information,

 

 

or use the DbProviderFactory.CreateAdapter

 

 

factory method (discussed in this recipe).

 

 

 

 

C H A P T E R 9 D ATA B A S E A C C E S S

329

The System.Data.Common.DbProviderFactory class is new to .NET Framework 2.0 and provides a set of factory methods for creating all types of data provider objects, making it very useful for implementing generic database code. Most important, DbProviderFactory provides a mechanism for obtaining an initial IDbConnection instance, which is the critical starting point to writing generic ADO.NET code. Each of the standard data provider implementations (except the SQL Server CE data provider) includes a unique factory class derived from DbProviderFactory. Here is the list of

DbProviderFactory subclasses:

System.Data.Odbc.OdbcFactory

System.Data.OleDb.OleDbFactory

System.Data.OracleClient.OracleClientFactory

System.Data.SqlClient.SqlClientFactory

You can obtain an instance of the appropriate DbProviderFactory subclass using the DbProviderFactories class, which is effectively a factory of factories. Each data provider factory is described by configuration information in the machine.config file similar to that shown here for the SQL Server data adapter. This can be changed or overridden by application-specific configuration information if required.

<configuration>

<system.data>

<DbProviderFactories>

<add name="SqlClient Data Provider" invariant="System.Data.SqlClient" description=".Net Framework Data Provider for SqlServer" type= "System.Data.SqlClient.SqlClientFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />

<add name="Odbc Data Provider" ... /> <add name="OleDb Data Provider" ... />

<add name="OracleClient Data Provider" ... /> <add name="SQL Server CE Data ... />

</DbProviderFactories>

</system.data>

</configuration>

You can enumerate the available data provider factories by calling DbProviderFactories. GetFactoryClasses, which returns a System.Data.DataTable containing the following columns:

Name, which contains a human-readable name for the provider factory. Taken from the name attribute in the configuration information.

Description, which contains a human-readable description for the provider factory. Taken from the description attribute of the configuration information.

InvariantName, which contains the unique name used to refer to the data provider factory programmatically. Taken from the invariant attribute of the configuration information.

AssemblyQualifiedName, which contains the fully qualified name of the DbProviderFactory class for the data provider. Taken from the type attribute of the configuration information.

Normally, you would allow the provider to be selected at install time or the first time the application was run, and then store the settings as user or application configuration data. The most important piece of information is the InvariantName, which you pass to the DbProviderFactories. GetFactory method to obtain the DbProviderFactory implementation you will use to create your

IDbConnection instances.

330 C H A P T E R 9 D ATA B A S E A C C E S S

Note Prior to .NET Framework 2.0, it was difficult to write generic ADO.NET code because each data provider implemented its own exception class that did not extend a common base class. In .NET Framework 2.0, the System.Data.Common.DbException class has been added as the base class of all data provider-specific exceptions, making generic handling of database exceptions a reality.

The Code

The following example demonstrates the enumeration of all data providers configured for the local machine and application. It then uses the DbProviderFactories class to instantiate a DbProviderFactory object (actually a SqlClientFactory) from which it creates the appropriate IDbConnection. It then uses the factory methods of the data provider interfaces to create other required objects, resulting in code that is completely generic.

using System; using System.Data;

using System.Data.Common;

namespace Apress.VisualCSharpRecipes.Chapter09

{

class Recipe09_10

{

public static void Main(string[] args)

{

//Obtain the list of ADO.NET data providers registered in the

//machine and application configuration file.

using (DataTable providers = DbProviderFactories.GetFactoryClasses())

{

// Enumerate the set of data providers and display details. Console.WriteLine("Available ADO.NET Data Providers:"); foreach (DataRow prov in providers.Rows)

{

Console.WriteLine(" Name:{0}", prov["Name"]); Console.WriteLine(" Description:{0}",

prov["Description"]); Console.WriteLine(" Invariant Name:{0}",

prov["InvariantName"]);

}

}

//Obtain the DbProviderFactory for SQL Server. The provider to use

//could be selected by the user or read from a configuration file.

//In this case, we simply pass the invariant name. DbProviderFactory factory =

DbProviderFactories.GetFactory("System.Data.SqlClient");

//Use the DbProviderFactory to create the initial IDbConnection, and

//then the data provider interface factory methods for other objects. using (IDbConnection con = factory.CreateConnection())

{

//Normally, read the connection string from secure storage.

//See recipe 9-3. In this case, use a default value. con.ConnectionString = @"Data Source = .\sqlexpress;" + "Database = Northwind; Integrated Security=SSPI";

C H A P T E R 9 D ATA B A S E A C C E S S

331

// Create and configure a new command. using (IDbCommand com = con.CreateCommand())

{

com.CommandType = CommandType.StoredProcedure; com.CommandText = "Ten Most Expensive Products";

//Open the connection. con.Open();

//Execute the command and process the results. using (IDataReader reader = com.ExecuteReader())

{

Console.WriteLine(Environment.NewLine); Console.WriteLine("Price of the Ten Most

Expensive Products.");

while (reader.Read())

{

// Display the product details. Console.WriteLine(" {0} = {1}",

reader["TenMostExpensiveProducts"],

reader["UnitPrice"]);

}

}

}

}

// Wait to continue. Console.WriteLine(Environment.NewLine); Console.WriteLine("Main method complete. Press Enter."); Console.ReadLine();

}

}

}

9-11. Discover All Instances of SQL Server on Your Network

Problem

You need to obtain a list of all instances of SQL Server 2000 or SQL Server 2005 that are accessible on the network.

Solution

Use the GetDataSources method of the System.Data.Sql.SqlDataSourceEnumerator class.

Note Your code needs to be granted FullTrust to be able to execute the GetDataSources method.

332 C H A P T E R 9 D ATA B A S E A C C E S S

How It Works

The addition of the new SqlDataSourceEnumerator class in .NET Framework 2.0 makes it easy to enumerate the SQL Server instances accessible on the network. In previous versions of the .NET Framework, you needed to create a COM Interop library to access the SQLDMO library to achieve this.

In .NET Framework 2.0, you simply obtain the singleton SqlDataSourceEnumerator instance via the static property SqlDataSourceEnumerator.Instance and call its GetDataSources method. The GetDataSources method returns a System.Data.DataTable that contains a set of System.Data.DataRow objects. Each DataRow represents a single SQL Server instance and contains the following columns:

ServerName, which contains the name of the server where the SQL Server instance is hosted.

InstanceName, which contains the name of the SQL Server instance or the empty string if the SQL Server is the default instance.

IsClustered, which indicates whether the SQL Server instance is part of a cluster.

Version, which contains the version of the SQL Server instance (8.00.x for SQL Server 2000 or 9.00.x for SQL Server 2005).

Caution It is possible to configure SQL Server 2005 to be invisible to the GetDataSources method by disabling the SQL Server Browser. Therefore, you cannot assume that a SQL Server instance does not exist because you could not discover it.

The Code

The following example demonstrates the use of the SqlDataSourceEnumerator class to discover and display details of all SQL Server instances accessible (and visible) on the network.

using System; using System.Data;

using System.Data.Sql;

namespace Apress.VisualCSharpRecipes.Chapter09

{

class Recipe09_11

{

public static void Main(string[] args)

{

// Obtain the DataTable of SQL Server instances. using (DataTable SqlSources =

SqlDataSourceEnumerator.Instance.GetDataSources())

{

// Enumerate the set of SQL Servers and display details. Console.WriteLine("Discover SQL Server Instances:"); foreach (DataRow source in SqlSources.Rows)

{

Console.WriteLine(" Server Name:{0}", source["ServerName"]); Console.WriteLine(" Instance Name:{0}",

source["InstanceName"]); Console.WriteLine(" Is Clustered:{0}",

source["IsClustered"]);

Console.WriteLine(" Version:{0}", source["Version"]);

}

}

C H A P T E R 9 D ATA B A S E A C C E S S

333

// Wait to continue. Console.WriteLine(Environment.NewLine); Console.WriteLine("Main method complete. Press Enter."); Console.ReadLine();

}

}

}

C H A P T E R 1 0

■ ■ ■

Networking and Remoting

The Microsoft .NET Framework includes a full set of classes for network programming. These classes support everything from socket-based programming with Transmission Control Protocol/Internet Protocol (TCP/IP) to downloading files and HTML pages from the Web over Hypertext Transfer Protocol (HTTP). Not only do these networking classes provide you with a rich set of tried-and-tested tools to use in your own distributed applications, they are also the foundation on which two highlevel distributed programming models integral to the .NET Framework are built: Remoting and XML Web services.

Although Remoting and XML Web services share many similarities (for example, they both abstract cross-process and cross-machine calls as method invocations on remote objects), they also have fundamental differences. XML Web services are built using cross-platform standards and are based on the concept of XML messaging. XML Web services are executed by the ASP.NET runtime, which means they gain ASP.NET features such as output caching. This also means that XML Web services are fundamentally stateless. Overall, XML Web services are best suited when you need to cross platform boundaries (for example, with a Java client calling an ASP.NET Web service) or trust boundaries (for example, in business-to-business transactions).

Remoting is a .NET-specific technology for distributed objects and is the successor to Distributed Component Object Model (DCOM). It’s ideal for in-house systems in which all applications are built on the .NET platform, such as the backbone of an internal order-processing system. Remoting allows for different types of communication, including leaner binary messages and more efficient TCP/IP connections, which aren’t supported by XML Web services. In addition, Remoting is the only technology that supports stateful objects and bidirectional communication through callbacks. It’s also the only technology that allows you to send custom .NET objects over the wire.

The recipes in this chapter describe how to do the following:

Obtain configuration and network statistic information about the network interfaces on a computer as well as detect when network configuration changes occur (recipes 10-1 and 10-2)

Download files from File Transfer Protocol (FTP) and HTTP servers (recipes 10-3, 10-4, and 10-6)

Respond to HTTP requests from within your application (recipe 10-5)

Send e-mail messages with attachments using Simple Mail Transfer Protocol (SMTP) (recipe 10-7)

Use the Domain Name System (DNS) to resolve a host name into an Internet Protocol (IP) address (recipe 10-8)

335

336C H A P T E R 1 0 N E T W O R K I N G A N D R E M OT I N G

Ping an IP address to determine whether it is accessible and calculate round-trip communication speeds by sending it an Internet Control Message Protocol (ICMP) Echo request (recipe 10-9)

Communicate between programs through the direct use of TCP in both synchronous and asynchronous communication models (recipes 10-10 and 10-11)

Communicate using User Datagram Protocol (UDP) datagrams where the connection-oriented and reliable TCP represents unnecessary overhead (recipe 10-12)

Write Web service proxy classes that read the Web service uniform resource locator (URL) from a configuration file, thus avoiding the need to rebuild code if the URL changes (recipe 10-13)

Provide credentials to allow a proxy class to authenticate against a secured Web service (recipe 10-14)

Call a Web service method asynchronously to avoid the calling code blocking and waiting for the Web service to respond (recipe 10-15)

Create remotable objects and register them with the .NET Framework’s Remoting infrastructure (recipes 10-16 and 10-17)

Host a remote object in Internet Information Services (IIS) (recipe 10-18)

Control the lifetime and versioning of remotable objects (recipes 10-19 and 10-20)

10-1. Obtain Information About the Local Network

Interface

Problem

You need to obtain information about the network adapters and network configuration of the local machine.

Solution

Call the static method GetAllNetworkInterfaces of the System.Net.NetworkInformation. NetworkInterface class to get an array of objects derived from the abstract class NetworkInterface. Each object represents a network interface available on the local machine. Use the members of each NetworkInterface object to retrieve configuration information and network statistics for that interface.

How It Works

The addition of the System.Net.NetworkInformation namespace in the .NET Framework 2.0 provides easy access to information about network configuration and statistics that was not readily available to .NET applications previously.

The primary means of retrieving network information are the properties and methods of the NetworkInterface class. You do not instantiate NetworkInterface objects directly. Instead, you call the static method NetworkInterface.GetAllNetworkInterfaces, which returns an array of

NetworkInterface objects. Each object represents a single network interface on the local machine. You can then obtain network information and statistics about the interface using the NetworkInterface members described in Table 10-1.

C H A P T E R 1 0 N E T W O R K I N G A N D R E M OT I N G

337

Tip The System.Net.NetworkInformation.IPGlobalProperties class (new to .NET 2.0) also provides access to useful information about the network configuration of the local computer.

Table 10-1. Members of the NetworkInterface Class

Member

Description

Properties

 

Description

Gets a string that provides a general description of the interface.

Id

Gets a string that contains the identifier of the interface.

IsReceiveOnly

Gets a bool indicating whether the interface can only receive or can

 

both send and receive data.

Name

Gets a string containing the name of the interface.

NetworkInterfaceType

Gets a value from the System.Net.NetworkInformation.

 

NetworkInterfaceType enumeration that identifies the type of interface.

 

Common values include Ethernet, FastEthernetT, and Loopback.

OperationalStatus

Gets a value from the System.Net.NetworkInformation.OperationalStatus

 

enumeration that identifies the status of the interface. Common values

 

include Down and Up.

Speed

Gets a long that identifies the speed (in bits per second) of the interface

 

as reported by the adapter, not based on dynamic calculation.

SupportsMulticast

Gets a bool indicating whether the interface is enabled to receive

 

multicast packets.

Methods

 

GetIPProperties

Returns a System.Net.NetworkInformation.IPInterfaceProperties

 

object that provides access to the TCP/IP configuration information for

 

the interface. Properties of the IPInterfaceProperties object provide

 

access to WINS, DNS, gateway, and IP address configuration.

GetIPv4Statistics

Returns a System.Net.NetworkInformation.IPv4InterfaceStatistics

 

object that provides access to the TCP/IP v4 statistics for the interface.

 

The properties of the IPv4InterfaceStatistics object provide access to

 

information about bytes sent and received, packets sent and received,

 

discarded packets, and packets with errors.

GetPhysicalAddress

Returns a System.Net.NetworkInformation.PhysicalAddress object that

 

provides access to the physical address of the interface. You can obtain

 

the physical address as a byte array using the method PhysicalAddress.

 

GetAddressBytes or as a string using PhysicalAddress.ToString.

Supports

Returns a bool indicating whether the interface supports a specified

 

protocol. You specify the protocol using a value from the System.Net.

 

NetworkInformation.NetworkInterfaceComponent enumeration. Possible

 

values include IPv4 and IPv6.

 

 

The NetworkInterface class also provides two other static members that you will find useful:

The static property LoopbackInterfaceIndex returns an int identifying the index of the loopback interface within the NetworkInterface array returned by GetAllNetworkInterfaces.

The static method GetIsNetworkAvailable returns a bool indicating whether any network connection is available, that is, has an OperationalStatus value of Up.

Соседние файлы в предмете Программирование на C++