Escolar Documentos
Profissional Documentos
Cultura Documentos
IO
Like most software, .NET Framework applications need some way to input and output data. These operations are most commonly done against a disk drive, but there are other possibilities too. The .NET Framework class library's ystem.!" namespace contains a substantial set of types that developers can use to read and write files, work with directories in a file system, and do other kinds of straightforward data access. File access is an essential service #mong the most fundamental of these types is the tream class. #s defined by this class, a stream is a se$uence of bytes together with methods to read the stream's contents, write those contents, perhaps seek to a specific location in the stream, and perform other operations. A Stream object contains a sequence of bytes and provides methods to access those bytes For e%ample, information stored in files can be accessed using the File class. &hile an instance of File provides familiar methods for working with files such as Create, Delete, and Open, it doesn't provide methods for reading and writing a file's contents. !nstead, a File ob'ect's (reate and "pen methods return an instance of a FileStream that can be used to get at the file's contents. Like all streams, a FileStream ob'ect provides Read and Write methods for synchronous access to a file's data, that is, for calls that block waiting for data to be read or written. #lso like other streams, FileStream ob'ects allow asynchronous access using the paired BeginRead/EndRead and BeginWrite/EndWrite methods. These methods allow a .NET Framework application to begin a read or write operation and then check later to get the result. Each FileStream also provides a eek method to move to a designated point in the file, a Flush method to write data to the underlying device )such as a disk drive*, a Close method to close the FileStream, and many more methods. A FileStream object allows access to a file's contents as binary data File treams work only with binary data, however, which isn't always what's needed. ystem.!" provides other standard classes to work with file data in other formats. For e%ample, the FileIn o class can be used to create FileStreams, but it can also be used to create instances of the classes StreamReader and StreamWriter. +nlike File, whose methods are mostly static, an instance of a File!nfo class must be e%plicitly created before its methods can be used. "nce a File!nfo ob'ect e%ists, its Open!e"t method can be used to create a new StreamReader ob'ect. This StreamReader can then be used to read characters from whatever file is associated with the FileIn o ob'ect. A FileInfo object allows access to a file's contents as text ,ere's a (- e%ample that illustrates how these classes can be used.
using System; using System.IO;
class FileIOExample { static void Main() { FileStream fs; FileInfo f; Stream eader sr; !yte"# !uf $ ne% !yte"&'#; string s; int i; for (i$'; i(&'; i))) !uf"i# $ (!yte) (*+ ) i); fs $ File.,reate(-test.dat-); fs..rite(!uf/ '/ &'); fs.,lose(); f $ ne% FileInfo(-test.dat-); sr $ f.Open0ext(); s $ sr. ead0oEnd(); 2 2 ,onsole..rite1ine(-{ '2 -/ s);
This admittedly unrealistic e%ample begins with appropriate using statements and then defines the single class File!"E%ample. This class contains only a /ain method, which begins with several declarations. #fter this, the 012byte buffer buf is populated with the characters 3#4 through 35.4 6ecause buf can accept only bytes, this is done by e%plicitly calculating each character's value and then forcing the result to be of type byte. )This forced type conversion is called casting.* File's (reate method is then used to create a file, followed by a call to File's &rite method. This method writes buf's ten characters into that file and is followed by a (lose call that closes the file. 6ecause the File class declares all of these methods to be static, they can be invoked without e%plicitly creating a File instance. The e%ample ne%t opens the same file using an instance of the File!nfo class. (alling the File!nfo ob'ect's "penTe%t method returns a tream7eader ob'ect whose 7eadToEnd method can be used to read the characters 'ust written into a string. tream7eaders also provide methods to read single characters, blocks of characters, and lines of characters. Finally, the characters read from the file are written to the console, yielding the result
34,5EF67I8
ystem.!" also defines several other useful types. The 8irectory class, for instance, provides methods such as (reate8irectory to create a new directory, 8elete to destroy an e%isting directory and its contents, and several more. The /emory tream class allows the typical operations defined for a stream, such as 7ead, &rite, and eek, to be carried out on an arbitrary set of bytes in memory. tring&riter and tring7eader provide analogous functions to tream&riter and tream7eader, e%cept that instead of working with files, they work with in2
memory strings. 6inary7eader and 6inary&riter allow reading and writing values of types such as integers, decimals, and characters from a stream. any other classes are also defined for wor!ing with files" directories" and streams &hile information stored in relational databases is more important for many applications, data stored in files still matters. The classes in ystem.!" provide a fle%ible set of options for working with that data.
Seriali#ation: System.Runtime.Seriali#ation
"b'ects commonly have state. #n instance of a class, for e%ample, can have one or more fields, each of which contains some value. !t's often useful to e%tract this state from an ob'ect, either to store the state somewhere or to send it across a network. 9erforming this e%traction is called seriali#ing an ob'ect, while the reverse process, recreating an ob'ect from seriali:ed state, is known as deseriali#ing Seriali#ation extracts an object's state The .NET Framework class library provides support for seriali:ation. The work of seriali:ation is done by a particular formatter$ each formatter provides a eriali:e and 8eseriali:e method. The NET Framework class library provides two varieties of formatter. The binary formatter, implemented by the 6inaryFormatter class in the System.Runtime.Seriali#ation.Formatters.Binary namespace, seriali:es an ob'ect into a straightforward binary form designed to be compact and $uick to parse. The "#9 formatter, implemented by the oapFormatter class in the System.Runtime.Seriali#ation.Formatters.Soap namespace, seriali:es an ob'ect into a "#9 message. A formatter can be used to seriali#e an object Figure ;20 illustrates the seriali:ation process. #s the figure shows, an instance of a class can be run through a formatter that e%tracts the state of this ob'ect in a particular form. #s 'ust stated, the binary formatter emits that state information in a simple and compact form, while the "#9 formatter generates the same information wrapped in </L and formatted as a "#9 message. &hile the outputs shown in the figure are simplified=the binary formatter actually stores integers in binary form, for instance=they illustrate the key difference between the two seriali:ation options built into the .NET Framework class library.
Figure 5-1. The System.Runtime.Serialization namespace provides two different formatters to serialize an ob ect!s state.
%oth a binary formatter and a S&A' formatter are provided &hen a formatter seriali:es an ob'ect, the resulting state is placed into a stream. #s described in the previous section, a stream is an abstraction of a se$uence of bytes and so can hold any seriali:ation format. "nce it's in a stream, an ob'ect's state can be stored on disk )or in the 'argon of ob'ects, be made persistent*, sent across a network to another machine, or used in some other way. An object's state is seriali#ed into a stream For a type to be seriali:able, its creator must mark it with the eriali:able attribute, as Figure ;20 illustrates. The eriali:able attribute can be assigned to classes, structures, and other types or 'ust to specific fields within a type to indicate that only they should be seriali:ed. #lso, a type marked with the eriali:able attribute can indicate that certain fields should not be saved when an instance of this type is seriali:ed by marking them with the Non eriali:ed attribute. (ot every type is seriali#able eriali:ation can also be customi:ed. For e%ample, if a class implements the ! eriali:able interface, it can participate in its own seriali:ation. This interface has only a single method that allows controlling the details of what gets seriali:ed. #lso, although it's not shown in this simple e%ample, seriali:ing an ob'ect will also seriali:e ob'ects it refers to, causing them all to be
seriali:ed )or deseriali:ed* at once. #nd for the brave of heart, it's possible to build your own formatter that does seriali:ation in a completely customi:ed way by inheriting from the abstract class ystem.7untime. eriali:ation.Formatter. ,owever it's done, seriali:ation is useful, and in its basic form, at least, it's simple to use. #s described later in this chapter, seriali:ation plays a role in several parts of the .NET Framework class library.
The familiar angle bracket form of </L implies a logical hierarchy of related information. This abstract set of information and relationships is known as the </L document's Information Set" a term that's usually shortened to 'ust Infoset. #n In oset consists of some number of information items" each of which represents some aspect of the </L document from which this !nfoset was derived. For e%ample, every !nfoset has a document information item that acts as the root of the tree, with a single root element information item 'ust beneath it. /ost !nfosets have some number of child element information items below this root element. An Infoset provides an abstract view of the information in an ) * document For e%ample, consider this simple </L document.
(employees9 (employee9 (name94o!(:name9 (age9;*(:age9 (:employee9 (employee9 (name9,asey(:name9 (:employee9 (:employees9
The !nfoset for this document can be represented as shown in Figure ;2>. The root of the !nfoset's tree is a document information item, while below it is a hierarchy of element information items, one for each element in the </L document. The leaves of the tree are the values of the elements in this simple document.
Figure 5-". #n $%& document!s 'nfoset is an abstract representation of the document!s contents.
</L documents and the !nfosets they imply can provide the foundation for tools that manipulate a document's data. #mong the most important of these is <9ath, which provides a mechanism for identifying a subset of an !nfoset. # simple and $uite accurate way to think of <9ath is as a $uery language for information in </L documents )that is, for </L !nfosets*. 5ust as ?L provides a standard language for $uerying information contained in a relational database, <9ath provides a language for $uerying information represented as a hierarchy. +sing an <9ath e%pression, a user can identify specific nodes in a tree. XPath allows querying an ) * document For e%ample, imagine that this $uery is issued against the simple </L document 'ust described.
:employees:employee:name
This simple <9ath re$uest first identifies each employee element below the root employees element and then identifies the values of each name element in each of those employee elements.
&ith <9ath, a developer need not write her own code to search through information. !nstead, this abstract language can be used to find easily information represented as an in2memory </L document. #nother technology built on the abstract foundation provided by </L In osets is the E"tensi*le Styles&eet )anguage !rans ormations, universally referred to as < LT. < LT is a mechanism for specifying transformations of </L documents, transformations that can be described in an < LT stylesheet. For instance, a set of < LT rules that transforms an </L document from one schema to another can be defined. < LT also relies on the abstract form of an </L document represented by its !nfoset, and it relies on <9ath for some of its functionality. )S*+ allows transforming ) * documents Figure ;2@ summari:es the relationships among the fundamental </L technologies. #n </L chema definition describes the structure and contents of an </L document=it defines a group of types=while an </L document itself can be thought of as an instance of the document type defined by some schema. This </L document, in turn, is the foundation for an !nfoset, which provides an abstract view of the document's data. Technologies for working with that data, such as <9ath and < LT, are effectively defined to work against the !nfoset, allowing them to remain independent of the specific representation used for the </L document itself. Note that because these technologies rely on the !nfoset rather than the familiar angle bracketAbased synta% of an </L document, they can actually be used with any data that can be represented in a strict hierarchy. That data need not necessarily come from a traditional </L document as long as it can be represented as an !nfoset. For e%ample, hierarchical data such as a file system or the &indows registry might be accessed in this way.
Figure 5-). $%& is a family of technologies* with the 'nfoset at the center.
The </L standards don't mandate any particular approach to processing the information in an </L document. #s it happens, two styles of #9!s have come into common use. !n one approach, the information in an </L document is read se$uentially, traversing a document's tree in a depth2first search. #n #9! that supports this kind of access is referred to as a streaming #9!, SA) is a streaming A'I for accessing ) *,defined information !n the second approach, the entire document is represented as an in2memory data structure )conceptually, at least*, which allows an application to navigate through it, moving back and forth as needed. The most commonly used #9! for this option is an implementation of the 8ocument "b'ect /odel )8"/* defined by the &@(. 6ecause of the style of access it allows, the 8"/ is an e%ample of a navigational #9!. +he -& is a navigational A'I for accessing ) *,defined information
<9ath $ueries, the ability to perform < LT transformations, and more. System.)ml includes support for )'ath" )S*+" the -& " and more The most fundamental types for handling </L2defined data are contained directly in ystem.<ml itself. "ne of these is the abstract class <mlNode. #s its name suggests, this class represents a node in an </L document, such as a particular element. #nother fundamental type in ystem.<ml is the abstract class <ml7eader. <ml7eader provides a streaming interface for accessing </L data. )Note that the .NET Framework does not directly support #<B instead it bases all streaming access on <ml7eader.* <ml7eader is the parent for three concrete classes.
'ml!e"tReader: 9rovides a streaming #9! that reads the information in an </L document se$uentially, much like the #< #9!. !t's the fastest option for reading </L2 defined data, but it's also somewhat limited in that no navigation is possible through the document. #lso, this class makes no attempt to determine whether the document is valid, that is, whether it corresponds correctly with some </L chema definition. 'ml+alidatingReader: Like <mlTe%t7eader, this class reads the information in an </L document se$uentially. !t also makes sure that the document corresponds to a specified </L chema definition, that is, that the document is valid. 'ml,odeReader: 7ather than reading from an </L document, this class provides forward2only access to a single <mlNode or a tree of <mlNodes. This is the same in2 memory structure used to represent an </L document accessed via the 8"/, but unlike the navigational 8"/ interface, <mlNode7eader allows only se$uential access.
+he )ml.eader class allows streaming access to ) *,defined information ystem.<ml also includes an abstract <ml&riter class, along with one implementation of a concrete class, called <mlTe%t&riter, that inherits from <ml&riter. The methods in this class allow writing </L information, angle brackets and all, to a stream. #s described earlier in this chapter, a stream can be maintained in memory, written to a file, or used in some other way. +he )ml/riter class allows writing ) * documents ystem.<ml also includes the <ml8ocument class. This class, which inherits from <mlNode, provides an implementation of the 8"/ #9!. &hile the various implementations of <ml7eader 'ust described are the fastest way to access information in an </L document, the <ml8ocument class is more general because it allows navigation, moving backward and forward through the document at will. # developer is free to choose whichever approach best meets the needs of his application. An )ml-ocument object allows navigational access to ) *,defined information The methods and properties provided by <ml8ocument give some idea of the kinds of operations the 8"/ allows. Those methods include the following.
)oad: Loads an </L document and parses it into its abstract tree form
Sa-e:
InsertBe ore: !nserts a new node, represented as an instance of the <mlNode class, in front of the currently referenced node in the tree Insert. ter: !nserts a new node, once again an <mlNode instance, in back of the currently referenced node in the tree Select,odes: #llows selecting nodes using an <9ath e%pression
<ml8ocument also e%poses a number of properties that allow navigation through the tree. They include the following.
/asC&ild,odes: !ndicates whether the current node has any nodes beneath it FirstC&ild: 7eturns the first child of the current node )astC&ild: 7eturns the last child of the current node 0arent,ode: 7eturns the parent, that is, the node immediately above the current node
System.'ml.Sc&ema: (ontains classes for creating and working with </L chema definitions. 6ecause this language is $uite comple%, this namespace contains a large set of classes, including a class for each of the elements in the </L chema language. /icrosoft refers to these classes collectively as the chema "b'ect /odel ) "/*. System.'ml.'0at&: (ontains types that support using <9ath e%pressions to $uery hierarchical data. #mong them are the <9athNavigator class, which allows navigating through a document and issuing <9ath $ueries, and the <9athE%pression class, which can contain a compiled <9ath $uery. System.'ml.'sl: (ontains types that support using < LT. The most important of these is the <slTransform class, which allows transforming data using an < LT stylesheet. System.'ml.Seriali#ation: (ontains types that allow seriali:ing data into an </L format. This is another large namespace, but a key type within it is the <ml eriali:er class. This class is similar to the oapFormatter class described earlier, in that it provides eriali:e and 8eseriali:e methods that write and read an ob'ect's state in </L. This namespace also contains many other classes that allow customi:ing the seriali:ation process, working with "#9, and other aspects of converting between state information stored in a language ob'ect and the seriali:ed </L form of that information.
+ypes for )'ath" )S*+" and ) * Schema support are provided in separate namespaces </L has become an essential part of modern computing. 6y providing a standard way to describe information, it fills an important hole in the comple%, multivendor world we live in. The
.NET Framework's large set of namespaces and types devoted to </L are intended to make this increasingly important technology significantly easier to use. +he .(0+ Framewor! class library has a great deal of support for ) *
#s you might e%pect, .NET 7emoting provides traditional remote procedure call )79(* functionality, allowing a client to invoke a method in a remote ob'ect and have some result returned. !t can also be used for asynchronous )nonblocking* calls, however, as well as one2way calls that have no result. The mission of .NET 7emoting is to make all of these interactions as simple yet as fle%ible as possible. .(0+ .emoting supports both synchronous and asynchronous communication
.(0+ .emoting is used for communication between different app domains &hen a client, such as an instance of some class, calls a method on an ob'ect in another app domain, that call is first handled by a proxy ob'ect running in the client's app domain. The pro%y represents the remote ob'ect in the client's app domain, allowing the client to behave as if that ob'ect were running locally. The (L7 automatically creates a pro%y by using reflection to access the metadata of the remote ob'ect being accessed. )Note what this implies. The assembly containing the remote ob'ect's classes andFor interfaces must be available on the client's machine.*
1lients rely on proxy objects # pro%y eventually hands a call's information to a channel ob'ect. The channel ob'ect is responsible for using some appropriate mechanism, such as a T(9 connection, to convey the client's re$uest to the remote app domain. "nce the re$uest arrives in that app domain, a channel ob'ect running there locates the ob'ect for which this call is destined, perhaps creating it if the ob'ect isn't already running. The call is then passed to the ob'ect, which e%ecutes it and passes any results back through the same path. 1ommunication is handled by channel objects #t a high level, the process is simple. !n fact, however, there's much more going on than this simple description shows. !t's possible, for instance, to insert code that intercepts and customi:es the in2progress call at several points in the path between caller and ob'ect. The details get $uite involved=remote access is never simple to implement well=but most of the comple%ity can remain invisible to developers using .NET 7emoting. The goal of this section is to present a broad overview of how this technology works. .(0+ .emoting provides many opportunities for customi#ation
!t's also possible to pass an instance of a reference type across an app domain boundary by reference. This option, called marshal by reference 3 %.4" is possible only if the reference type inherits from /arshal6y7ef"b'ect, a class contained in the ystem namespace. &hen an /67 ob'ect is passed across an app domain boundary, only a reference to the ob'ect is passed. This reference, which is more comple% than the one used to refer to the ob'ect in its own app domain, is used to construct a pro%y back to the original ob'ect in its home app domain. &hen code in the remote app domain references this ob'ect, such as by calling one of its methods, those references are actually sent back to the original instance of this ob'ect. 9assing /67 ob'ects as parameters makes sense in cases where the overhead of accessing the ob'ect remotely is less than the cost of making a copy of the ob'ect. arshal by reference passes only a reference to another app domain Figure ;2H illustrates the difference between /6G and /67 ob'ects. &hen ob'ect <, an /6G ob'ect in app domain 0, is passed to app domain > as a parameter on a call to ob'ect ", a copy of < is created in the remote app domain. 9assing ob'ect D, however, does not result in a copy of D being created in app domain > because D is an /67 ob'ect. !nstead, a pro%y to D is created, and all accesses to ob'ect D are sent back to the instance of D in app domain 0. )#lthough it's not shown in the picture, communication from D's pro%y back to D itself relies on channels, 'ust as described earlier.*
Figure 5-/. %arshal by value ob ects are copied when passed across an app domain boundary* while marshal by reference ob ects have a pro.y created for them in the remote app domain.
Finally, if a user2defined type isn't seriali:able and doesn't inherit from /arshal6y7ef"b'ect, it is neither an /6G nor an /67 ob'ect. !n this case, instances of that type can't be marshaled across an app domain boundary at all. !n other words, any instance of this type can be used only within the app domain in which it is created. (ot all types can be marshaled
#hoosing a #hannel
#pplications using .NET 7emoting ultimately rely on channels to convey calls and responses between app domains. Two standard channels, called the +1' channel and the 5++' channel" are provided, and it's also possible to build custom channels. .(0+ .emoting provides a +1' channel and an 5++' channel &hile not especially simple to create, a custom channel might provide security services such as encryption, use a nonstandard protocol, or perform some other function in a uni$ue way. !t's safe to assume, however, that most applications will work happily with one of the two choices built into the .NET Framework. The !C0 c&annel is the simpler of the two. 6y default, it seriali:es and deseriali:es a call's parameters using the binary formatter described earlier in this chapter, although the "#9 formatter can also be used. "nce the parameters have been seriali:ed, they're transmitted directly in T(9 packets. omewhat surprisingly, the T(9 channel provides no built2in support for authentication, data encryption, or any other security feature. +he +1' channel sends binary information directly over +1' The second option, the /!!0 c&annel, uses the "#9 formatter by default to seriali:e and deseriali:e a call's parameters. 7ather than sending those parameters directly over T(9, they're sent as "#9 re$uests and responses embedded in ,TT9. !t's also possible to use the binary formatter with the ,TT9 channel, which can be very useful. The binary formatter is more efficient than the "#9 formatter, so if the .NET Framework is on both sides of the communication, this option makes sense. For applications that need distributed security, the ,TT9 channel can use the security options provided by !nternet !nformation ervices )!! *. !n this case, one possibility is to use the ecure ockets Layer ) LL* protocol with ,TT9, an option sometimes referred to as ,TT9 . +he 5++' channel sends S&A' envelopes over 5++' 8eciding which channel to use depends on your goals. !f the communication is entirely within an organi:ation's intranet=if no firewalls will be traversed=use the fast and simple T(9 channel. !f the communication must go through firewalls, however, as do most packets sent on the !nternet, use the ,TT9 channel. #lthough it's a bit less efficient, riding on ,TT9 means passing through port I1, the only port that virtually all firewalls leave open /hich channel is best depends on the situation !t's also possible to use different kinds of channels from the same app domain. This allows clients to communicate with remote ob'ects using the mechanism that's most appropriate for each one. # single client, for instance, might use the more efficient T(9 channel to talk to an ob'ect within the firewall while also invoking methods in an ob'ect across the !nternet via the ,TT9 channel.
Single1call o*2ects: # new instance of the class is created for each call from each client and then is destroyed )that is, made available for garbage collection* when the call ends. Singleton o*2ects: "nly one instance of the class is created on a given machine, and that same instance handles all calls made by all clients to that class on this machine. Client1acti-ated o*2ects: # separate instance of the class is created for each client that wishes to use it and then is destroyed only when that client is finished with it.
7egardless of which option is chosen, the server will create each new ob'ect on its own thread. #lso, any ob'ect that will be accessed from outside its app domain must be an /67 ob'ect, which means that the class must inherit from /arshal6y7ef"b'ect. These similarities notwithstanding, how ever, each of these options varies in who creates the ob'ect, how the ob'ect is destroyed, as well as in other ways. #ccordingly, each is worthy of its own short discussion.
upport for )possibly distributed* transactions 5ust2in2time activation )5!T#*, which optimi:es server resources by allowing ob'ects to e%ist only when they're needed "b'ect pooling, which allows instances of a class to be pooled and reused rather than being destroyed and recreated 7ole2based authori:ation services that allow ("/J to verify a client's role and then grant services only to clients in specific roles
1lasses that use 1& 6 services are !nown as serviced components erviced components can also use ("/J services that aren't directly related to building robust server applications, such as $ueued components, which is effectively an #9! to /icrosoft /essage ?ueuing )/ /?*B an event serviceB and others.The key point is that .NET Enterprise ervices allows managed code to use all ("/J services, but those services are unchanged= the .NET Framework doesn't add any new features in this area. "ne of the innovations brought by ("/J )or more correctly, by /icrosoft Transaction erver, the original incarnation of this technology* was the ability to control what services a component received by setting attributes in a configuration file. To control how transactions are used, for e%ample, a developer using ("/J can set a transaction attribute to 7e$uired, indicating that all methods in this component should be run within a transaction. &hen the component is e%ecuted, ("/J reads this attribute and provides the re$uested transaction support. !n traditional ("/J, these attributes are stored in something called the ("/J catalog, and they're typically set using the ("/J E%plorer, a configuration tool designed for this purpose. +raditional 1& 6 uses attributes to specify what services an application needs !n the .NET Framework, however, attributes are supported directly. #s every assembly can have e%tra metadata represented as attributes. #lso, attribute values can be set in the source code of a (L72based application=there's no need for a separate configuration tool=and those values can be read at runtime using reflection. 6uilt2in support for attributes matches well with how ("/J provides its services, and so .NET's Enterprise ervices e%ploit this feature of the (L7. 8evelopers are now able to specify how ("/J services should be used by including attributes directly in their code. #nd because it's sometimes useful to be able to change a component's attributes after the assembly that contains it has been installed, the ("/J E%plorer can still be used to set or modify a component's attributes if desired. Serviced components use the 1*.'s built,in attributes to specify what services an application needs ,ere's a simple G6.NET class that shows how attributes can be used to control the use of ("/J transactions.
(0ransaction(0ransactionOption. e<uired)9 = >u!lic ,lass 4an?3ccount In@erits Serviced,omponent (3uto,omplete()9 = >u!lic Su! 5eposit(3ccount 3s Integer/ = 3mount 3s 5ecimal) A 3dd 3mount to 3ccount End Su! (3uto,omplete()9 = >u!lic Su! .it@dra%al(3ccount 3s Integer/ = 3mount 3s 5ecimal) A Su!tract 3mount from 3ccount
This class, called 6ank#ccount, inherits from erviced(omponent, as is re$uired for any (L72 based class that wishes to use ("/J services. The class definition is also preceded with an attribute indicating that this class uses the 7e$uired setting for transactions. This means that whenever a client calls one of the class's methods, ("/J will automatically wrap the work done by that method in the all2or2nothing embrace of a transaction. The two methods in this simple class, 8eposit and &ithdrawal, each begins with the #uto(omplete attribute )and since this is 'ust an e%ample, the code for these methods is omitted*. This attribute indicates that if the method returns an e%ception, the serviced component will vote to abort the transaction of which it's a part. !f the method completes normally, however, this component will vote to commit the transaction to which it belongs. Note that different attributes are applied at different levels. The Transaction attribute, for e%ample, can be applied only to a class=it can't be set per method=while #uto(omplete can be applied only on a per2method basis. !f the developer of this application wished to add a method to check the balance, she might well choose to put this method in some other class. #dding it to the 6ank#ccount class would re$uire the method to use a transaction, which isn't generally necessary for this kind of simple read operation so it would needlessly hurt performance. Attributes can be used to specify a class's transactional requirements /any other attributes are available for controlling aspects of a serviced component's behavior. For e%ample, the 5ust!nTime#ctivation attribute allows turning 'ust2in2time activation on and off )although this feature is automatically turned on for classes that use transactions*, while the "b'ect9ooling attribute controls whether pooling is used and, if it is, how large the pool will be. "ther available attributes set application2wide options such as the name of the application as seen by ("/J. Attributes can also be used to specify the use of other 1& 6 services !n standard ("/J, an interface called !"b'ect(onte%t contains fundamental methods that components can use. 9erhaps the most important of these are et(omplete and et#bort, the two methods that allow a component to cast its vote in a transaction if the autocomplete option isn't used. !n .NET Enterprise ervices, these same methods are available through a class called (onte%t+til. !f a transactional method wishes to control its commitment behavior e%plicitly, it can do so by directly calling these methods. +he methods in the traditional I&bject1ontext interface are still available #s mentioned earlier, the implementation of ("/J services is not managed code in the first release of the .NET Framework. !n spite of this, serviced components are able to use those services without leaving the managed environment. #s Figure ;2K shows, key ("/J services such as transactions are provided using conte%t information maintained by ("/J itself in un managed code. &hen this conte%t is accessed, such as when a serviced component votes to commit or abort a transaction, that re$uest flows across the boundary between managed and
unmanaged code. !nteractions among serviced components, however, remain completely within the managed environment provided by the (L7. ince crossing into unmanaged code incurs a slight performance penalty, this ability to remain almost entirely within the managed space is a good thing.
Figure 5-3. -(%4 maintains conte.t information for serviced components* allowing it to provide services across the managed5unmanaged boundary.
1& 6 has not been completely rewritten as managed code Enterprise ervices also has a few more artifacts of its foundation in unmanaged code. For e%ample, when a serviced component is accessed remotely, that access relies on 8("/ rather than on .NET 7emoting. imilarly, serviced components must have entries in the &indows registry, like traditional ("/J components but unlike other .NET classes. These entries can be created and updated automatically by the Enterprise ervices infrastructure=there's no need to create them manually=but re$uiring them at all betrays this technology's ("/ foundations. !t's likely that all of these limitations will change in a future release of the .NET Framework when ("/J is completely rewritten in managed code. .emote access to serviced components is via -1&
Interopera*ility: System.Runtime.InteropSer-ices
&indows 8N# is a successful group of technologies. Lots of applications that were built using ("/, #ctive erver 9ages, ("/J, and the rest of the 8N# family e%ist. /any of these applications play an important role in running businesses, so they're certain to remain in use for at least the ne%t few years. No matter how successful the .NET Framework is, the &indows 8N# technologies that preceded it are not going away anytime soon. Software using pre,.(0+ technologies will not just disappear Civen the huge investment /icrosoft's customers have made in these applications, the .NET Framework must provide some way for new applications to connect with them. 5ust as important, the Framework must provide an effective way for managed code to access e%isting 8LLs that weren't built using ("/ and to invoke the raw services provided by the underlying operating system. olutions to all of these problems are provided by the classes in the ystem.7untime.!nterop ervices namespace. +he types in System..untime.,InteropServices allow interoperability with existing software
8oing this can be simple. !n some cases, mapping from a ("/ interface to a (L7 type is straightforward. !t can also be $uite difficult, however, especially when the ("/ interface involved uses comple% types. &hile it's virtually always possible to map the two together in some way, it isn't always easy. To make even difficult mappings possible, the classes in ystem.7untime.!nterop ervices provide very fine2grained control over how the mapping is done as well as many, many options. &hile most people won't use most of these options most of the time, it's still good to know that they're available. apping between 1& and managed objects can be simple" but it can also be complex
The fundamental model for interoperation between managed code and ("/2based code is that each side sees the other in the form it e%pects. /anaged code sees ("/2based code as managed types, while ("/2based code sees managed code as ("/ ob'ects. ,ow this looks is shown in Figure ;201. To provide this illusion, the .NET Framework relies on two kinds of wrappers. "ne, known as a runtime callable wrapper 3.1/4" allows managed code to call a ("/ ob'ect. The other, a 1& callable wrapper 311/4" allows ("/ code to access managed code.
Figure 5-16. The .12T Framewor7!s -(% interoperability services can ma7e a -(% ob ect loo7 li7e managed code and managed code loo7 li7e a -(% ob ect.
code and managed code each see the other as being li!e themselves
6ut where does the information needed to create these wrappers come fromL /anaged code sees the world in terms of assemblies, so to access a ("/ ob'ect as managed code, an assembly that mimics the ("/ class must e%ist. Furthermore, this assembly must contain metadata that accurately reflects the ("/ class's interfaces. To create this interoperability assembly, the .NET Framework provides a tool called Tlbimp, also known as the Type Library !mporter. The input to this tool is a ("/ type library, and the output is an assembly that contains metadata for the (L7 analogs of the ("/ types in the type library. +ools create wrappers for 1& objects
"nce this assembly has been created, managed code can treat the library's ("/ classes 'ust like any other managed code. &hen the managed code creates an instance of the class, the 7(& actually creates the ("/ ob'ect. &hen the managed code invokes a method, the 7(& makes a corresponding method invocation on the ("/ ob'ect. !f an error occurs and the ("/ method returns an error ,7E +LT, as ("/ re$uires, the 7(& automatically turns this into an
e%ception that can be caught by the managed code. #nd when the managed code is finished using the ob'ect, it can behave 'ust as it does when using any other managed ob'ect. The 7(& will decrement the ("/ ob'ect's reference count before it is itself destroyed by the (L7's garbage collector. +he wrapper maps between 1& 's behavior and what managed code expects &hen a ("/ client uses a managed class, the same kinds of things happen in the opposite direction. 7ather than producing an assembly from a type library, the developer can now produce a type library from an assembly. The Type Library E%porter tool, known as Tlbe%p, provides one way to do this. #lso, because ("/ uses the registry to determine which code should be loaded for a particular class, assemblies that will be accessed by ("/ clients must have appropriate registry entries. The #ssembly 7egistration Tool, 7egasm, can be used to do this and optionally to register the assembly's generated type library as well. &hen a ("/ client creates and uses an instance of a managed class, translations between the two worlds are performed as before, but this time they're done by the ((& rather than the 7(&. +ools also create wrappers for managed objects #ll of this sounds simple and straightforward, and it often is. Det what's not been addressed so far is the process of converting between the (L7 type system and the ("/ type system. /uch as with .NET 7emoting, data must be marshaled between the two environments by the wrappers. 8efault mappings are defined, and if those defaults work, using code from the other world is simple. /arshaling an integer, for e%ample, is straightforward, since a value of this type is the same in both environments. !f the default mappings aren't appropriate, however, a developer's life gets more comple%. &hat should a (L7 string map to in the ("/ world, for e%ampleL ("/ has more than one string format, and it's not always obvious which one should be used. To control this and other marshaling choices, a developer can use the /arshal#s attribute to indicate the choice she prefers. Figuring out the right thing to do isn't always easy, but the fine2grained control the types in this namespace provide at least makes it possible. A developer can customi#e the mapping between these two environments "ne last point worth noting is that making calls across the boundary between managed and unmanaged code is noticeably more e%pensive than making calls solely within either environment. /arshaling data between the two takes timeB writing managed code that interoperates with unmanaged code has performance implications. !t's a good idea to do as much work as possible on each call across this boundary. !f each one does only a small amount of work, an application that makes a large number of calls between the two worlds is unlikely to perform especially well. 1alls between managed and unmanaged code are expensive
Forms and controls also support events. ome e%amples of common events include (lick, indicating that a mouse click has occurredB CotFocus, indicating that the form or control has been selected by the userB and Mey9ress, indicating that a key has been pressed. !n fact, all of these events and several more are defined in the base (ontrol class from which all &indows Forms controls inherit. # control can also support uni$ue events that have meaning only to it. %oth forms and controls can respond to events # developer can create code to handle events received by a form or control. (alled an event handler" this code determines what happens when the event occurs. ,andling events relies on delegates, the type provided by the (L7 for passing references to methods in a type2safe way. 1ode that responds to events is called an event handler
/indows Forms controls can emulate Active) controls !n &indows 8N#, Gisual 6asic and (JJ had completely different approaches to building C+!s. 6ecause of this, #ctive< controls were based on ("/, which allowed them to work with both languages. The predictable result was comple%ity. &indows Forms sweeps away the accumulation of C+! technologies that have built up on the &indows platform, replacing them with a single consistent approach. &hile you may lament the effort re$uired to learn this new approach, there is certainly some appeal in finally having 'ust one way to build &indows user interfaces. /indows Forms provides a common mechanism for creating 78Is in any 1*.,based language