Deserializing XML The XmlSerializer.Deserialize method converts an XML document into an object of the appropriate type: public class CarFromFile { public static void Main{ XmlSerial
Trang 1Chapter 17: XML 789
The Model.Horsepower property is associated with the [XmlIgnore]
attribute, which specifies that the XmlSerializer not include the property in the
XML document
Deserializing XML
The XmlSerializer.Deserialize( ) method converts an XML document into an
object of the appropriate type:
public class CarFromFile {
public static void Main(){
XmlSerializer xs = new XmlSerializer(typeof(Car)); FileStream str =
new FileStream("car.xml", FileMode.Open);
Car c = (Car) xs.Deserialize(str);
Can’t serialize cycles
This is a perfectly legitimate object-oriented relationship:
Trang 2790 Thinking in C# www.ThinkingIn.NET
In this relationship, a Yang contains a reference to a Yin and a Yin to a Yang It
is possible for both objects to contain references to each other; the data structure
may have a cycle
XML does not use references to relate objects, it uses containment One object
contains another, which in turn contains its subobjects There are no references
native to XML If the XmlSerializer detects a cycle, it throws an
InvalidOperationException, as this example demonstrates:
public Yang Yang{
get{ return yang;}
set { yang = value;}
public Yin Yin{
get{ return yin;}
set { yin = value;}
}
public Yang(){
}
public static void Main(){
Yin yin = new Yin();
Yang yang = new Yang();
Trang 3use of unique text-based ids in lieu of references, the use of [XmlIgnore] and
the dynamic “reattachment” of references based on the XML Ids
Throughout this book, we’ve often used the phrase “This is an example of the X
design pattern.” Here, we have what seems to be the opposite case, a situation where we see a common problem (XML serialization of cyclical references) and can identify a path towards a general solution There’s a certain temptation to
design something and present it as “the Mock Reference pattern” (or whatever)
However, probably the most distinctive feature of the seminal books in the
patterns movement (Design Patterns and Pattern-Oriented Software
Architecture) is that they were based on software archaeology; patterns were recognized in existing, proven software solutions There are no NET patterns yet
and very few XML patterns; there simply has not been enough time for a variety
of design templates to prove themselves in the field
Having said that, let’s take a crack at a serializable Yin-Yang object structure: //:c17:SerializedYinYang.cs
// Can serialize cycles
using System;
using System.IO;
using System.Collections;
using System.Xml.Serialization;
public class Yin {
static Hashtable allYins = new Hashtable();
public static Yin YinForId(Guid g){
return(Yin) allYins[g];
}
Yang yang;
public Yang Yang{
get{ return yang;}
set {
yang = value;
}
Trang 4792 Thinking in C# www.MindView.net
}
Guid guid = Guid.NewGuid();
[XmlAttribute]
public Guid Id{
get { return guid;}
public Yin Yin{
get{ return yin;}
set { yin = value;}
}
public Guid YinId{
get { return yin.Id;}
Trang 5Chapter 17: XML 793
[XmlAttribute]
public Guid Id{
get { return guid;}
set { guid = value;}
}
public Yang(){
}
public static void Main(){
Yin yin = new Yin();
Yang yang = new Yang();
Yang newYang = newYin.Yang;
Yin refToNewYin = newYang.Yin;
if (refToNewYin == newYin) {
Console.WriteLine("\nCycle re-established"); }
Trang 6794 Thinking in C# www.ThinkingIn.NET
This program relies on the Guid structure, which is a “globally unique identifier”
value; both classes have Id properties associated with the
XmlAttributeAttribute that can serve to uniquely identify the objects over
time.2 The Yin class additionally has a static Hashtable allYins that returns
the Yin for a particular Guid The Yin( ) constructor and the Yin.Id.set
method update the allYins keys so that allYins and YinForId( ) properly
return the Yin for the particular Guid
The Yang class property Yin is marked with [XmlIgnore] so that the
XmlSerializer won’t attempt to do a cycle Instead, Yang.YinId is serialized
When Yang.YinId.set is called, the reference to Yang.Yin is reestablished by
calling Yin.YinForId( )
The Yang.Main( ) method creates a Yin and a Yang, establishes their cyclical
relationship, and serializes them to a MemoryStream The MemoryStream
is printed to the console, gets its Position reset, and is then passed to
XmlSerializer.Deserialize( ), creating new Yin and Yang objects Although
newYin and newYang have the same Id values and the same cyclical
relationships that the original yin and yang had, they are new objects, as Figure
17-3 illustrates
2 It’s theoretically possible for GUIDs generated at different times to have the same value,
but it’s exceedingly rare That’s why GUIDs are only “globally” and not “universally”
unique
Trang 7Chapter 17: XML 795
yang : YangYang.Main yin : Yin allYins xs :
XmlSerializernew
new[yinGuid] = yin
Yang = yang
Yin = yin
Serialize(yin)Deserialize(memStream)
newYang :Yang
newId.set(yinGuid)
[yinGuid] = null
changes "official"
Yin for yinGuidfrom yin to newYin[yinGuid] = newYin
newYinId.set(yinGuid)Get(yinGuid)
newYinnewYin : Yin
newYin
Trang 8796 Thinking in C# www.MindView.net
Figure 17-3: Reconstructing cycles from an XML document
The output of the program looks like this, although the Guids will be different:
So far, the only restriction that we’ve placed on the XML is that it be well formed
But XML has an additional capability to specify that only elements of certain
types and with certain data be added to the document Such documents not only
are well formed, they are valid XML documents can be validated in two ways,
via Document Type Definition (DTD) files and via W3C XML Schema (XSD) files
The XML Schema definition is still quite new, but is significantly more powerful
than DTDs Most significantly, DTDs are not themselves XML documents, so you
can’t create, edit, and reason about DTDs with the same tools and code that you
use to work with XML documents
An XML Schema, on the other hand, is itself an XML document, so working with
XML Schemas can be done with the same classes and methods that you use to
work with any XML document Another advantage of XML Schemas is that they
provide for validity checking of the XML data; if the XML Schema specifies that
an element must be a positiveInteger, then a variety of tools can validate the
data flowing in or out of your program to confirm the element’s values
This XML Schema validates the data of the CarStructure example:
Trang 10798 Thinking in C# www.ThinkingIn.NET
We aren’t going to go over the details, because you’ll never have to handcraft an
XML Schema until you’re working at a quite advanced level The NET
Framework SDK comes with a tool (xsd.exe) that can generate an XML Schema
from an already compiled NET assembly This example was generated with this
command line:
xsd CarStructure.exe
More commonly, you’ll be working in a domain with a standards group that
produces the XML Schema as one of its key technical tasks If given an XML
Schema, the xsd tool can generate classes with public properties that conform to
the XML Schema’s specification In practice, this rarely works without
modification of the schema; whether the fault lies in the xsd tool or the
widespread lack of experience with XML Schema in vertical industries is difficult
to say
You can also use the xsd tool to generate a class descended from type DataSet
As discussed in Chapter 10, a DataSet is an in-memory, disconnected
representation of relational data So with the xsd tool, you can automatically
bridge the three worlds of objects, XML, and relational data
ADO and XML
From the discussion of ADO in Chapter 10, you’ll remember that a DataSet is an
in-memory representation of a relational model An XmlDataDocument is an
XML Doocument whose contents are synchronized with a DataSet, changes to
the XML data are reflected in the DataSet’s data, changes to the DataSet’s data
are reflected in the XmlDataDocument (as always, committing these changes
to the database requires a call to IDataAdapter.Update( ))
This example quickly revisits the Northwind database and is essentially a rehash
of our first ADO.NET program (you’ll need a copy of NWind.mdb in the current
Trang 11private static DataSet Employees(string fileName){
OleDbConnection cnctn = new OleDbConnection();
After retrieving a DataSet filled from the Employees table using the same
ADO.NET code shown in Chapter 10,3 we create a new XmlDataDocument that is linked to the DataSet ds We then use DataSet.WriteXml( ) and DataSet.WriteXmlSchema( ) to present the XML view of the DataSet (an
3 Well, almost the same Instead of “SELECT * FROM EMPLOYEES” we limit the data to first and last names because the EMPLOYEES table contains photographs that make the returned XML unwieldy
Trang 12A DataSet can also directly read an XML stream, either validating it against an
existing schema or inferring a schema from the data Here, the car.xml becomes
the source of a DataSet and its inferred schema written to the screen:
//:c17:CarDataSet.cs
//Demonstrates DataSet from XML
using System;
Trang 13public static void Main(){
DataSet carDataSet = new DataSet();
Combined with the BindingContext class discussed in Chapter 14, NET’s
powerful infrastructure for XML, data, and display is beginning to fall into place The final piece of the puzzle will have to wait until the next chapter, with our discussion of Web Services that use XML as the native “language” of Web-based conversations
XPath navigation
While SQL is the native means of navigating relational data, XPath is the native means of navigating XML data Since XML has a treelike structure, the natural way to get from one place to another is to specify a “path” up-or-down the branches from either the current Node or from the root Element XPath is not itself expressed as an XML Document, rather it is reminiscent of file-system navigation commands
The simplest XPaths are those that specify an absolute path to an object Given this XML:
<!DOCTYPE set SYSTEM "docbookx.dtd">
Trang 14The XPath statement /set/chapter/title selects the titles of all the chapters
The command //title on the other hand, selects all title elements, including the
title element that is contained below the bookinfo node
The asterisk (*) command selects all elements contained within the specified
path; //bookinfo/* selects the title, author, and copyright elements
You move about an XmlDocument (or any other object that implements
IXPathNavigable) via an XPathNavigator This is the same philosophy that
gives rise to the use of IEnumerators on collection classes – separating the
issues of traversal from the issues of the data structure However, XPath takes
this one step further: The XPathNavigator is responsible for selecting a
Trang 15Chapter 17: XML 803
particular node, the XPathNavigator then produces an XPathNodeIterator
to actually move about relative to the position selected by the XPathNavigator
These relationships are illustrated in Figure 17-4, which illustrates the behavior
Trang 16804 Thinking in C# www.MindView.net
Car Vin = “12345678”
Model Mileage CruiseControl
Units = “Miles”
Data = 80000 Make
Data = “Civic”
Manufacturer Data = “Honda”
Year Data = “1992”
myNavigator.Select( )
myIterator :
XPathNodeIterator
myDocument : XmlDocument
Figure 17-4: Navigating with XPathNodeIterator
The CarNavigator( ) constructor loads the data structure from the car.xml
file XmlDocument.CreateNavigator( ) is a factory method that generates
the XPathNavigator The XPathNavigator.Select( ) is given an argument
that translates as “select all the children nodes of all the Model nodes.”
There’s an overloaded version of XmlDocument.CreateNavigator( ) that
takes a reference to an XmlNode as an argument; it creates an
XPathNavigator whose context node is not the root node (as was the case in
the previous example) but the passed-in XmlNode This allows you to work with
subsets of a large XML document The next example uses this method to create
an XPathNavigator that navigates across a specific sale from the Northwind
database Additionally, the XPath selection statement in this example uses an
argument to qualify the nodes returned by XPath.Select( ) When an XPath
expression is qualified with square bracket notation, the contents of the square
brackets are logically evaluated In addition to logical expressions, 1-based index
values can be used Thus //chapter[3] or //chapter[title=‘Hello, Objects!’] both
select the third chapter of this book’s Docbook representation In this example,
this type of XPath qualifier is used to select only the sales of a particular
Trang 17private static void SelectSalesByLastName(
XmlDataDocument doc, string lastName){
XPathNavigator nav = doc.CreateNavigator(); string xPathSel =
"{0} {1} sold for delivery on {2}",
fName, lName, delDate);
Trang 18806 Thinking in C# www.ThinkingIn.NET
"SELECT FirstName, LastName, OrderDate FROM"
+ " EMPLOYEES, ORDERS where "
This example starts similarly to the previous Northwind examples, except instead
of just loading data from the Employees table, this time the SQL SELECT
statement joins the employees and their orders The resulting dataset is
approximately 800 lines long
After the DataSet is returned to the NWindNavigator( ) constructor, the
constructor creates an XmlDataDocument synchronized with the DataSet
This XmlDataDocument and the last name of one salesperson become
arguments to NWindNavigator.SelectSalesByLastName( )
The NWindNavigator.SelectSalesByLastName( ) method constructs an
XPath selector of the form:
//Table[LastName=’Callahan’]
which creates an XPathNodeIterator for “Every node that is a Table and which
in turn has a LastName child node whose value is ‘Callahan.’”
We are not interested in the Table node, of course, we are interested in its
children nodes: the FirstName, LastName, and DeliveryDate nodes To
navigate to them, we clone XPathNodeIterator.Current and call the resulting
XPathNavigator saleNav We use XPathNavigator.MoveToFirstChild( )
and XPathNavigator.MoveToNext( ) to traverse the instance of the Table
node We write to the screen the values of the various nodes in this sub-tree
This combination of XPathNavigator.Select( ),
XPathNodeIterator.MoveNext( ), and XPathNavigator.MoveToXxx( )
methods is typical of use The XPathNavigator.MoveToXxx( ) methods are
Trang 19XPath syntax has a few other tricks:
♦ The at symbol (@) is used to specify an attribute Thus, you might select
a specific car by using /Car[@VIN=“12345678”] or a specific yin node with /yin[@Id=“8342aaa3-31e4-4d56-95fc-0959301a7ccf”>
♦ You can combine paths with the vertical bar operator (|) //chapter |
//preface selects all elements that are either chapters or prefaces
♦ The XPath axes child, descendant, parent, ancestor,
following-sibling, and preceding-sibling can be used to select nodes that have
the appropriate structural relationship with the specified node
/set/book/chapter[1]/following-sibling selects the second chapter of the
book (remember that XPath indices are
1-based, so chapter[1] selects the first chapter) The child axis is the
default axis and need not be specified
An XPath explorer
The best way to understand XPath is to experiment This program loads XML
documents into a TreeView control, and highlights element nodes
corresponding to the XPath selection statement you type into the provided
Trang 20808 Thinking in C# www.MindView.net
readonly Color DEFAULT_BACKCOLOR = Color.White;
readonly Color HIGHLIGHT_FORECOLOR = Color.Blue;
readonly Color HIGHLIGHT_BACKCOLOR = Color.Red;
internal XmlTreeView(XmlDocument src){
Init(src);
}
private void Init(XmlDocument src){
doc = new XmlDocument();
string eType = nav.Name;
string eVal = nav.Value;
string nodeText = eType + ": " + eVal;
XmlTreeNode node = null;
Trang 21internal void ResetFormatting(){
foreach(TreeNode node in Nodes){
Trang 22class XmlTreeNode : XmlElement {
internal XmlTreeNode(string val, XmlDocument doc)
Text = "XPath Explorer";
XmlDocument doc = new XmlDocument();
Trang 23MainMenu mainMenu = new MainMenu();
MenuItem fMenu = new MenuItem("&File");
MenuItem exit = new MenuItem("E&xit");
exit.Click += new EventHandler(AppClose); fMenu.MenuItems.Add(exit);
Menu = mainMenu;
}
void NewXPath(object src, EventArgs e){
string xPath = xPathText.Text;
tl.Highlight(xPath);
}
void FileOpen(object src, EventArgs e){
OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = "XML files (*.xml)|*.xml";
ofd.FilterIndex = 1;
Trang 24The concept of this program is that a TreeView with its TreeNodes is
conceptually similar to an XmlDocument with its XmlNodes To bridge the
gap between the two classes, we create XmlTreeView, a type of TreeView that
contains a reference to an XmlDocument, and a bunch of XmlTreeNodes, a
type of XmlElement that contains a reference to a TreeNode An
XPathNavigator selects the XmlNodes in the XmlDocument, selected
XmlNodes that are of type XmlTreeNode change the appearance of their
corresponding TreeNode:
Trang 25Chapter 17: XML 813
Figure 17-5: The class structure of XmlTreeView
The first task is populating a TreeView with the elements from an
XmlDocument XmlTreeView.Init( ), which the XmlTreeView( )
constructor calls, creates a new XmlDocument called doc The passed-in
XmlDocument src is used as the basis for an XPathNavigator that will walk over all of its nodes, while the XmlTreeView’s inherited TreeNodeCollection nodes is the source of the TreeNodes Init( ) calls
XmlTreeView.PopulateNodeFromTreeSet with hthese three arguments,
XPathNavigator nav, XmlNode doc (upcast from XmlDocument), and
TreeNodeCollection Nodes
XmlTreeView.PopulateNodeFromTreeSet( ) iterates over each XmlNode
in the XPathNavigator nav nodeset A new XmlTreeNode is created for each node in the nodeset The XmlTreeNode( ) constructor in turn creates a new
TreeNode The TreeNode is appended to the passed-in TreeNodeCollection and the XmlTreeNode is appended to the XmlDocument doc If the node
has children, the method clones the XPathNavigator and recursively calls
itself, this time with arguments set to the cloned XPathNavigator (pointing to a child node of the original XmlDocument), the just-created XmlTreeNode,
and a reference to the just-created TreeNode The end result is that
TreeView
XmlTreeView
Sets appearance Selects
Trang 26814 Thinking in C# www.ThinkingIn.NET
XmlDocument doc contains XmlTreeNodes, each of which maintains a
reference to its TreeNode
When someone calls XmlTreeView.Highlight( ) with a string argument
corresponding to an XPath selector, the first step is to reset the formatting of
each TreeNode in the XmlTreeView This is done with a recursive call to
XmlTreeView.ResetNodeFormatting( ), which simply sets the colors of
each TreeNode to their defaults Once XmlTreeView.Highlight( ) has reset
the colors, it calls XmlDocument.CreateNavigator( ) on the
XmlDocument doc, which contains nothing but XmlTreeNodes So the
XPathNodeIterator created by XPathNavigator.Select( ) traverses over a
bunch of XmlTreeNodes Each XmlNode returned is downcast to
XmlTreeNode and the appearance of its corresponding TreeNode is changed
to highlight the selection
When run, the program provides an easy-to-use explorer of XPath functionality:
Figure 17-6: The XPath Explorer sample in action
Trang 27Chapter 17: XML 815
Transforming a document
In addition to using XPath to select and navigate XML nodes, the NET
Framework provides the System.Xml.Xsl namespace4 for transforming XML documents with Extensible Stylesheet Language Transformations (XSLT) XSLT
is a declarative programming language that transforms XML documents from one form to another The most common use of XSLT is to transform an XML document into a form suitable for display Often, this means transforming it into XHTML, an XML-ified version of HTML Blogs, for instance, typically use XML
as their native storage format and use XSLT for the presentation
The principle of separating domain data from presentation logic is one that we have praised in Chapter 14 Unfortunately, XSLT has not “broken out” as a mainstream technology for Web design; it is not supported in the major tools used by Web designers, the percentage of browsers incapable of displaying XSLT-based pages remains at least in the high teens, and the search engines have difficulty indexing XML-based sites Although you can set things up so that the XSLT transformation occurs at the server if the client is using a non-compliant browser, the burden imposed can be significant, especially if you’re really trying
to exploit the power of XSLT During the writing of this book, we changed the
www.ThinkingIn.Net site from an XML and XSLT solution to straight HTML,
primarily because of the search engine problem and the performance hit of server-side conversion
Microsoft’s decision to ship an XSLT class in the NET Framework initially seems
a little out of step with the lack of success of XSLT as a display technology, especially as Microsoft seems to be moving away from client-side XSLT towards Cascading Style Sheets (CSS) as the preferred mechanism for styling XML for browser display However, the key is the deep relationship between
XmlDocuments and DataSets, especially in the XmlDataDocument class,
which synchronizes changes between XML and relational data Rather than
viewing XslTransform just as a tool for creating interfaces, it is better to think
of it as the final piece of the data-manipulation puzzle; you may be just as likely
to use an XslTransform to restructure a database as to create a Web page
In this example, we use a DataRelation to retrieve more than one table from
the Northwind relational database
//:c17:TwoTables.cs
4 The namespace should be called Xslt since it does not support XSL Formatting Objects
Trang 29Chapter 17: XML 817
DataRelation rel = new DataRelation(
"EmpOrder",
ds.Tables["Employees"].Columns["EmployeeId"], ds.Tables["Orders"].Columns["EmployeeId"]);
Trang 30Both <Employees> and <Orders> elements are placed as immediate children
of the root node <TwoTables> The following XSLT program is designed to
transform the output of the TwoTables example:
<! Transforms EmpOrd.XML output from TwoTables.cs
Trang 31<EmployeeOrders> element are filled with the results of applying templates to the nodeset specified in the <xsl:apply-templates select="./Employees"> The second template matches each of these <Employees> nodes The second
template shows some additional capabilities of the XSLT language: variables, whitespace output, and the ability to explicitly call a template rather than rely on
XPath selectors The second template calls the OrdsForId template with the value of the empId variable that reflects the <EmployeeId> node in the original XML document OrdsForId uses this value to create an XPath selector
that retrieves the orders for the particular employee The final template of the
stylesheet creates an <Order> element with an Id attribute and a <SaleDate> element that corresponds to the original <OrderDate> element
This program applies the stylesheet, saved in a file named EmpOrd.xsl, to the EmpOrd.xml data produced by the TwoTables program:
Trang 32public static void Main(){
XslTransform xslt = new XslTransform();
QuickTransform creates an XslTransform object and loads the XSL
stylesheet An XPathDocument provides a fast, read-only IXPathNavigable
object intended especially for XSLT processing XslTransform.Transform( )
works with any IXPathNavigable object (including XmlDocument and
XmlDataDocument), but XPathDocument is preferred for high-speed
transformation
The second argument to XslTransform.Transform( ) is an
XsltArgumentList that allows you to extend the power of the XslTransform
object; such extensions are beyond the range of this discussion
When run, this program transforms the output of TwoTables into an XML
document of the form:
Trang 33While you could achieve this type of output by manipulating an XmlDocument
programmatically, once understood, XSLT makes XML transformations much easier than the equivalent direct programming tasks
Summary
XML is a non-compact, text-based format for specifying structured data Its strengths come from its readability, editability, and structure, which is neither relational nor object-oriented but close enough to bridge these worlds and flexible enough to be viewed as either a stream or as a treelike structure XML itself is not all that interesting, but XML is the lingua franca for an entire
generation of emerging data-interchange standards
The NET Framework allows you to work with XML as either a stream, using XmlTextReader and XmlTextWriter, or as a tree, using XmlDocument,
which encapsulates the Core of W3C DOM Levels 1 and 2 Additionally, the NET Framework exposes several pieces of core functionality in XML forms; objects can be serialized to and from XML, as can ADO.NET data
The advantage of viewing an XML document as a tree is that you can apply various traversals and transformations to it, using the same principles that apply
to all data structures (see Chapter 10) In particular, XPath is an XML
specification that allows you to specify complex traversals that are themselves expressed in XML and XSLT allows you to specify complex transformations in XML
The advantage of viewing an XML document as a stream is that it makes driven processing simple, and one can begin acting on XML data before (and whether or not) a complete document has been read This is particularly valuable when moving XML to and from a network connection, but may also be the right approach any time XML documents will grow very large
event-XML has emerged as the de facto standard for serializing data over the Web, but XML does not have a native way to express the full complexity of object-oriented data structures, such as reference cycles in which two objects refer to each other
Trang 34822 Thinking in C# www.ThinkingIn.NET
If these sorts of things are necessary to the application, they must be added
programmatically
Although XML is not a perfect solution, it has absolutely exploded onto the
programming scene and will dominate over-the-net data transfer for the next
decade at least Because NET embraces XML as the glue that binds stream,
database, and object models together, it is important to develop a good
understanding of XML’s strengths and weaknesses
Exercises
1 Investigate XML specifications in an industry or topic in which you are
interested Possibilities range from education (the Schools
Interoperability Framework at http://www.sifinfo.org/ ) to travel (the Open Travel Alliance at http://www.opentravel.org/ ) to chemistry (Chemical Markup Language at http://www.xml-cml.org/ )
2 Write a program that compares the time needed to count the number of
nodes in a large XML document using an XmlTextReader based) with the time required by an XmlDocument (document-based)
(stream-approach
3 Modify the program in the previous example to select a random number
of nodes (say, 100) and prints these nodes to the screen Compare the times required by the stream-based versus document-based approach
4 Write a program that creates an XML document that represents a deck of
5 Write a program to shuffle the “deck of cards” created in the previous
example This will require investigating the difficulties associating with creating a “perfect” shuffle algorithm
6 Create an XML schema that describes the “deck of cards” from the
previous examples
Trang 359 Write a program that ranks the five-card hands from the previous
exercises according to standard poker rules
10 Using what you have learned from the previous exercises, estimate the
feasibility of creating an XML standard for the description of card games
Trang 36in two directions: onto the server and into post-desktop devices such as handhelds, tablets, and phones The NET Framework makes programming for both these worlds straightforward Programming non-desktop devices does not rely on radically different “enterprise” or “mobile” programming models or types Rather, attributes,
managed memory and threading, the scalable database architecture of ADO.NET, and the power of XML are
added to the solid object-oriented support of the C#
language
Network programming in NET is easy; a characteristic of networked NET applications is how little code is devoted to network-specific issues This trend is
taken to its extreme with the WebMethodAttribute, which makes a method
Web-callable with 11 keystrokes.1 Although WebMethodAttribute is likely to
be the most commonly used way you will expose methods to the Web, we’re going
to give a Cook’s tour of more explicit ways to send data over the network
Trang 37Chapter 18: Web Programming 825
unique machines within the local network However, with IP (Internet Protocol) becoming by far the most common way of connecting computers, every machine
in the world can have a unique identity This is accomplished with the IP address,
a 32-bit number that is expressed in the “dotted quad” format that has become so familiar.2 Even more often, the DNS (Domain Name Service) is used to look up the particular IP address of a human-readable name such as
www.ThinkingIn.Net
.NET provides the IPAddress class to encapsulate the address You can create
an IPAddress for a specific 32-bit number, but you are far more likely to use IPAddress.Parse( ) method to create an IPAddress from a dotted-quad string or the Resolve( ) or GetHostByName( ) methods of the Dns class The following program uses Dns.GetHostByName( ) to produce your IP
addresses To use it effectively, you need to know the name of your computer
You can find this in the Computer Name tab in the My Computer
public static void Main(string[] args){
string machineName = args.Length == 0 ?
2 Curiously, NET’s IPAddress class uses a 64-bit long rather than a 32-bit uint to store
this number This is especially curious because IPv6, the long-awaited replacement of the
32-bit IPv4 is 128 bits in length, so it’s not a case of the class having forward compatibility
Trang 38826 Thinking in C# www.ThinkingIn.NET
In addition to an address, IP uses a second more-specific location called a port,
which is supposed to allow fine-tuning of what services are made available to the
outside world Of course, most system administrators are paranoid about
opening ports to the outside world, perhaps because they do not understand that
a process must be listening at the port to introduce a vulnerability.3 This has
created the absurd situation where there are more services than ever, but the
majority of them are “tunneled” through the Web Server at port 80, thus
reducing the ability of system administrators to quickly gain a clear picture of
what services are causing what activity on the network
Sockets
Data sent over the Internet is split into datagrams, each of which contains a
header containing addressing information and a payload containing data The
developers of Berkeley UNIX did a great service to the world by abstracting all
the bookkeeping details associated with acknowledging, retrying, and
reassembling all this data so that it appears as a stream no different than that
which is read from a local file system The facility for doing this is called Berkeley
sockets and NET exposes them via Socket and related classes in the
System.Net.Sockets namespace
In the NET Framework, you use a socket to connect two machines, then you get a
NetworkStream that lets you treat the socket like any other IO stream object
You get this NetworkStream from an even higher-level abstraction than
Socket, though: a TcpListener that a server uses to listen for incoming
connections, and a TcpClient that a client uses in order to initiate a
conversation Once a client makes a socket connection, the TcpListener returns
(via the AcceptTcpClient( ) method) a corresponding server-side TcpClient
through which direct communication will take place From then on, you have a
TcpClient to TcpClient connection and you treat both ends the same At this
point, you use TcpClient.GetStream( ) to produce the NetworkStream
objects from each TcpClient You will usually decorate these with buffers and
formatting classes just like any other stream object described in Chapter 12
Whois for ZoneAlarm
This example shows how easy it is to write a socket-based utility using the
TcpClient class Most people do not have a dedicated firewall machine at their
3 Although even one open port makes the server or network visible and thus potentially a
target However, if you run a Web server, your potential enemies will know your IP
address
Trang 39Chapter 18: Web Programming 827
home While Windows XP provides a personal firewall, for various reasons one of use (Larry) runs ZoneAlarm from Zone Labs While the payware version of
ZoneAlarm provides a whois program for determining information on specific
IP addresses, it is a manual process After seeing a surprisingly large volume of alerts logged; he wanted to see if any addresses in particular were causing
trouble This program extracts IP addresses from the ZoneAlarm logfile, counts the number of events from that IP and, if the number of events exceeds a
threshold, runs a whois query on the IP address:
Hashtable sources = new Hashtable();
StreamReader log = GetFile();
string line = null;
int i = 0;
while ((line = log.ReadLine()) != null) {
BlockInfo info = BlockInfo.Build(line);
if (info != null && info is FWin) {
Trang 40public static void Main() {
ZALogAnalyzer prog = new ZALogAnalyzer();
prog.ReadFile();
}
}
class BlockInfo {
private const int I_FWIN = 14;
//Can't be instantiated by others