Pro Visual C++-CLI And The .NET 2.0 Platform (2006) [eng]-1
.pdfC H A P T E R 1 3 ■ X M L |
599 |
Let’s expand on this expression just a little more. It is also possible to have conditionals with logical operators such as and, or, and not().
The following method shows the logical operator in practice. It also shows how to grab an attribute value out of the navigator:
void GetGoblinSuccubusHitDice(XPathNavigator ^nav)
{
XPathNodeIterator ^list =
nav->Select("//Monster[Name='Goblin' or Name='Succubus']/HitDice");
Console::WriteLine("\nGoblin & Succubus HD\n-----------"); while (list->MoveNext())
{
XPathNavigator ^n = list->Current; n->MoveToFirstAttribute(); Console::WriteLine(n->Value);
}
}
Figure 13-11 shows the output of the snippet.
Figure 13-11. Output for the XPath expression //Monster[Name='Goblin' or Name='Succubus']/HitDice
To match attributes in an XPath expression, use the “at” sign (@) in front of the attribute’s name. For example,
void GetGoblinSuccubusHitDice(XPathNavigator ^nav)
{
XPathNodeIterator ^list =
nav->Select("//Monster[Name='Goblin' or Name='Succubus']/HitDice/@Dice");
Console::WriteLine("\nGoblin & Succubus HD\n----------"); while (list->MoveNext())
{
XPathNavigator ^n = list->Current; Console::WriteLine(n->Value);
}
}
results in the same output as the previous example. Notice that you no longer have to move to the attribute before displaying it.
As a final example, the following snippet shows that you can make numeric comparisons. In this example, I grab all Weapon elements with a Number attribute of less than or equal to 1:
600 C H A P T E R 1 3 ■ X M L
void GetSingleAttackWeapons(XPathNavigator ^nav)
{
XPathNodeIterator ^list =
nav->Select("//Weapon[@Number <= 1]"); |
|
Console::WriteLine("\nSingle Attack Weapons\n---------- |
"); |
while (list->MoveNext()) |
|
{ |
|
XPathNavigator ^n = list->Current; |
|
Console::WriteLine(n->Value); |
|
} |
|
} |
|
Figure 13-12 shows the output of the snippet.
Figure 13-12. Output for the XPath expression //Weapon[@Number <= 1]
Table 13-4 is a list of the available operators that you have at your disposal when developing your XPath expressions.
Table 13-4. XPath Operators
Operator Description
|Compute the union of node sets; for example: //monsters | //players would return a node set containing all monster and players (if players were part of the DOM)
+Addition
-Subtraction
*Multiplication
div Division
=Equals
!= |
Not equals |
<Less than
<= |
Less than or equal to |
>Greater than
>= |
Greater than or equal to |
or |
Or |
C H A P T E R 1 3 ■ X M L |
601 |
Table 13-4. XPath Operators
Operator |
Description |
and |
And |
mod |
Modulus (remainder) |
not |
Negation |
|
|
XML and ADO.NET
This topic almost doesn’t merit a section of its own, as only one class, XmlDataDocument, needs to be examined, and XmlDataDocument inherits from XmlDocument. What am I trying to get at? To use ADO.NET and XML together, you need to create a DataSet (see Chapter 12) and create an XmlDataDocument with it. Then you can manipulate the database data just as you did with XmlDocument.
The XmlDataDocument class adds properties and members to streamline some activities and to make them more “relational database”–like, but other than that you have already learned what you need to work with XML originating from an ADO.NET database:
•DataSet is the DataSet used to create the XmlDataDocument.
•CreateEntityReference() is a method that is not supported and throws an exception.
•GetElementById() is a method that is not supported and throws an exception.
•GetElementFromRow() gets an XmlElement associated with a specified DataRow.
•GetRowFromElement() gets a DataRow associated with a specified XmlElement.
•Load() loads into the XmlDocument using a filename, Stream, TextReader, or XmlReader, and then synchronizes with the DataSet.
The example in Listing 13-13 is an exact duplicate of Listing 13-9, except that the source of the XML data is the DCV_DB database created in Chapter 12.
Listing 13-13. Dumping the DCV_DB Database to a Console Using XML
using namespace |
System; |
using namespace |
System::Data; |
using namespace |
System::Data::SqlClient; |
using namespace |
System::Xml; |
String ^indent(int depth) |
|
{ |
|
String ^ind |
= ""; |
return ind->PadLeft(depth*4, ' ');
}
void Navigate(XmlNode ^node, int depth)
{
if (node == nullptr) return;
602 C H A P T E R 1 3 ■ X M L
Console::WriteLine("{0}: Name='{1}' Value='{2}'", String::Concat(indent(depth),node->NodeType.ToString()), node->Name, node->Value);
if (node->Attributes != nullptr)
{
for (int i = 0; i < node->Attributes->Count; i++)
{
Console::WriteLine("{0}Attribute: Name='{1}' Value='{2}'", indent(depth+1),node->Attributes[i]->Name, node->Attributes[i]->Value);
}
}
Navigate(node->FirstChild, depth+1); Navigate(node->NextSibling, depth);
}
void main()
{
XmlDocument ^doc = gcnew XmlDocument();
try
{
SqlConnection ^connect = gcnew SqlConnection();
#ifdef SQLAuth |
|
|
// |
SQL Server authentication |
|
connect->ConnectionString = |
||
|
"User ID=sa; Password=;" |
|
|
"Data Source=(local); Initial Catalog=DCV_DB;"; |
|
#else |
|
|
// |
Windows Integrated Security |
|
connect->ConnectionString = |
||
|
"Persist Security Info=False; Integrated Security=SSPI;" |
|
|
"Data Source=(local); Initial Catalog=DCV_DB;"; |
|
#endif |
|
|
SqlDataAdapter ^dAdapt = gcnew SqlDataAdapter(); |
||
DataSet ^dSet |
= gcnew DataSet(); |
|
dAdapt->SelectCommand |
= |
gcnew SqlCommand("SELECT * FROM Authors", connect);
dAdapt->Fill(dSet, "Authors");
XmlDataDocument ^doc = gcnew XmlDataDocument(dSet);
// Recursive navigation of the DOM tree Navigate(doc->DocumentElement, 0);
}
catch (Exception ^e)
{
Console::WriteLine("Error Occurred: {0}", e->Message);
}
}
604 C H A P T E R 1 3 ■ X M L
reading from, updating, and writing to them. Next, you took a brief look at the powerful XPath. You finished off by learning how simple it is to manipulate ADO.NET databases using XML.
Now with all four I/O systems covered, you should have no problems getting the necessary information into your system.
In the next chapter, you will explore the first of two service types covered in this book, the Windows service.
606 C H A P T E R 1 4 ■ W I N D O W S S E R V I C E S
users working on the computer. Also, due to the fact that the Windows service has no interface, it is ideal for running in the background thread on a server. Since I do not cover multithreading until later in the book (Chapter 16), I will not the cover placing of a Windows service in a background thread, but after you have read Chapter 16, you should have little difficulty doing so.
■Note Not having an interface, though, does not make an application a service. Console applications can be written without an interface as well. Typically, services provide system-level support, including a system event log, performance counters, and a task scheduler, but again that does not make an application a service either.
As mentioned previously, a Windows service is installed into the registry as an executable object. As you will see, the main() method does not actually run the service; instead, it is used to install the service into the registry. To actually start a Windows service, you will need to use either the Services application, which is part of the Administrative Tools on the Control Panel (see Figure 14-1), or create your own service control application. (You can also configure your Windows service to automatically start at startup as well.)
Figure 14-1. The Administrative Tools’ Services application
In case you are interested, all Windows services installed on a computer can be found in the registry at
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services
There are several different types of Windows services that can be created, but only two managed code types can be created with the .NET Framework. A Windows service made up of only a single service in a process is of type Win32OwnProcess, while a Windows service made up of multiple services in a single shared process is of type Win32ShareProcess.
C H A P T E R 1 4 ■ W I N D O W S S E R V I C E S |
607 |
You can find out the type of Windows service you are accessing by querying the property ServiceController.ServiceType. If the service was not created by .NET, then it is possible for this property to have other values as listed in Table 14-1.
Table 14-1. Windows Service Types
ServiceType |
Description |
Adapter |
A service for a piece of hardware that needs its own driver. |
FileSystemDriver |
A file system driver. This is a specific type of kernel driver. |
InteractiveProcess |
A service that can communicate with the desktop. |
KernelDriver |
A low-level hardware device driver. |
RecognizerDriver |
A file system driver used during the system startup to determine file |
|
system types. |
Win32OwnProcess |
A service made up of only a single service in a process. |
Win32ShareProcess |
A service made up of multiple services in a single shared process. |
|
|
Architecture of Windows Services
Unlike other application types, Windows services actually require three different programs to function properly. The first program is the service application itself. This program implements the functionality required by the Windows service. The second program is the service control application. This program provides the ability to start, pause, restart, stop, and send unique commands to the service application. The final program is the service configuration application. This program installs and configures the service application.
Service Application
The service application provides the functionality of the Windows service. But since it is a registry executable object, it is internally set up a little differently from other applications. The service application is also made up of three parts: the main, the service-main, and the handlers.
The main part provides the ability to register the true entry point or points of the service application, the service-main or service-mains. This dual functionality is required because a Windows service can be either of type Win32OwnProcess or Win32ShareProcess. Thus, when the Windows service is of type Win32OwnProcess, the main part must register the single service-main that makes up the Windows service. On the other hand, when the Windows service type is Win32ShareProcess, then the main part must register the multiple services that comprise the Windows service.
The service-main is the Windows service’s interface to the outside world and is called when the service needs to be started. Once called, the service-main then needs to register a handler to the Service Control Manager (SCM).
The SCM is part of the operating system that communicates with the Windows service. It is the SCM that sends events to the third part of the service application, the handler. It is up to the handler to handle the start, pause, continue, stop, and custom events sent to it from the SCM.