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

Pro CSharp 2008 And The .NET 3.5 Platform [eng]

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

862 CHAPTER 24 PROGRAMMING WITH THE LINQ APIS

static void LoadExistingXml()

{

//Build an XElement from string. string myElement =

@"<Car ID ='3'> <Color>Yellow</Color> <Make>Yugo</Make>

</Car>";

XElement newElement = XElement.Parse(myElement); Console.WriteLine(newElement); Console.WriteLine();

//Load the SimpleInventory.xml file.

XDocument myDoc = XDocument.Load("SimpleInventory.xml"); Console.WriteLine(myDoc);

}

Source Code The LinqToXmlBasics example can be found under the Chapter 24 subdirectory.

Navigating an In-Memory Document

So, that this point you have seen various ways in which LINQ to XML can be used to create, save, parse, and load XML data. The next aspect of LINQ to XML we need to examine is how to navigate a given document to locate specific elements/attributes. While the LINQ to XML object model provides a number of methods that can be used to programmatically navigate a document, not too surprisingly LINQ query expressions can also be used for this very purpose.

Since you have already seen numerous examples of building query expressions, the next example will be short and sweet. First, create a new Console Application named NavigationWithLinqToXml and import the System.Xml.Linq namespace. Next, add a new XML document into your current project named Inventory.xml, which supports a small set of entries within the root <Inventory> element. Here is one possibility:

<?xml version="1.0" encoding="utf-8"?> <Inventory>

<Car carID ="0"> <Make>Ford</Make> <Color>Blue</Color> <PetName>Chuck</PetName>

</Car>

<Car carID ="1"> <Make>VW</Make> <Color>Silver</Color> <PetName>Mary</PetName>

</Car>

<Car carID ="2"> <Make>Yugo</Make> <Color>Pink</Color> <PetName>Gipper</PetName>

</Car>

<Car carID ="55"> <Make>Ford</Make> <Color>Yellow</Color>

CHAPTER 24 PROGRAMMING WITH THE LINQ APIS

863

<PetName>Max</PetName>

</Car>

<Car carID ="98"> <Make>BMW</Make> <Color>Black</Color> <PetName>Zippy</PetName>

</Car>

</Inventory>

Now, select this file within the Solution Explorer and use the Properties window to set the Copy to Output Directory property to Copy Always (to ensure a copy of the file ends up in your Bin folder). Finally, update your Main() method to load this file into memory using XElement.Load(). The local doc variable will be passed into various helper methods to modify the data in various manners:

static void Main(string[] args)

{

Console.WriteLine("***** Fun with LINQ to XML *****\n");

//Load the Inventory.xml document into memory.

XElement doc = XElement.Load("Inventory.xml");

//We will author each of these next...

PrintAllPetNames(doc);

Console.WriteLine();

GetAllFords(doc);

Console.ReadLine();

}

The PrintAllPetNames() method illustrates the use of the XElement.Descendants() method, which allows you to directly specify a given subelement you wish to navigate to in order to apply a LINQ query expression. Here we are selecting each PetName value and printing out the contents to the console:

static void PrintAllPetNames(XElement doc)

{

var petNames = from pn in doc.Descendants("PetName") select pn.Value;

foreach (var name in petNames) Console.WriteLine("Name: {0}", name);

}

The GetAllFords() method is very similar in nature. Given the incoming XElement, we define a where operator and select the all XElements where the Make element is equal to the value "Ford":

static void GetAllFords(XElement doc)

{

var fords = from c in doc.Descendants("Make") where c.Value == "Ford"

select c;

foreach (var f in fords) Console.WriteLine("Name: {0}", f);

}

Figure 24-12 shows the output of this program.

864 CHAPTER 24 PROGRAMMING WITH THE LINQ APIS

Figure 24-12. LINQ to XML in action

Modifying Data in an XML Document

Finally, as you would hope, LINQ to XML provides numerous ways to insert, delete, copy, and update XML content. Adding new XElements to an existing XElement (or XDocument) is no harder than calling the Add() method, which adds the data to the end of the element/document. As an alternative, you can call AddFirst() to add the item to the top of the element/document or AddAfterThis()/ AddBeforeThis() to insert data at a specific location.

Updating or deleting content is also very straightforward. After constructing a LINQ query statement to identify the item (or items) you wish to tinker with, simply call ReplaceContent() (for updating) or Remove()/RemoveContent() (for deletion of data). By way of a simple example, consider the following code, which adds a set of new <Car> elements to the incoming XElement parameter:

static void AddNewElements(XElement doc)

{

// Add 5 new purple Fords to the incoming document. for (int i = 0; i < 5; i++)

{

//Create a new XElement

XElement newCar =

new XElement("Car", new XAttribute("ID", i + 1000), new XElement("Color", "Green"),

new XElement("Make", "Ford"), new XElement("PetName", "")

);

//Add to doc.

doc.Add(newCar);

}

// Show the updates.

Console.WriteLine(doc);

}

That wraps up our look at the major LINQ APIs that ship with .NET 3.5, and this chapter as well! Over the remainder of this book, you will find various LINQ queries where appropriate; however, be aware that each of the APIs examined here (LINQ to DataSet, LINQ to SQL, and LINQ to XML) are extensively documented in the .NET Framework 3.5 SDK documentation.

Source Code The NavigationWithLinqToXml to XML example can be found under the Chapter 24 subdirectory.

CHAPTER 24 PROGRAMMING WITH THE LINQ APIS

865

Summary

This chapter extended your understanding of LINQ by introducing three LINQ-centric APIs. We began by examining how to transform an ADO.NET DataSet into a LINQ-compatible container using the AsEnumerable() extension method. Once you have extracted an IEnumerable<T> type, you are able to apply any flavor of LINQ query.

Closely related to LINQ to DataSet is the LINQ to SQL API. This aspect of LINQ not only allows you to apply query expressions to data held within relational databases, it also provides infrastructure that essentially encapsulates all trace of the underlying ADO.NET data types. As you have seen, the DataContext type can be used to perform all of the expected database operations, including invoking stored procedures.

We wrapped up by examining LINQ to XML. Similar to LINQ to SQL, this API can be used either to apply LINQ queries to data within an XML document or to build XML documents in a functional manner. The end result is an extreme simplification of how the .NET platform supports the manipulation of XML documents.

C H A P T E R 2 5

Introducing Windows Communication

Foundation

.NET 3.0 introduced an API specifically for the process of building distributed systems named Windows Communication Foundation (WCF). Unlike other distributed APIs you may have used in the past (DCOM, .NET remoting, XML web services, etc.), WCF provides a single, unified, and extendable programming object model that can be used to interact with a number of previously diverse distributed technologies.

This chapter begins by framing the need for WCF and examining the problems it intends to solve by way of a quick review of previous distributed computing APIs. After we look at the services provided by WCF, we’ll turn to examine the .NET assemblies (and core types) that represent this programming model. Over the remainder of this chapter, we’ll build several WCF services, hosts, and clients using various WCF development tools.

Note This chapter will provide you with a firm foundation in WCF development. However, if you require a comprehensive treatment of the subject, check out Pro WCF: Practical Microsoft SOA Implementation by Chris Peiris and Dennis Mulder (Apress, 2007).

A Potpourri of Distributed Computing APIs

The Windows operating system has historically provided a number of APIs for building distributed systems. While it is true that most people consider a “distributed system” to involve at the very least two networked computers, this term in the broader sense can simply refer to two executables that need to exchange data, even if they happen to be running on the same physical machine. Using this definition, selecting a distributed API for your current programming task typically involves asking the following pivotal question:

Will this system be used exclusively “in house,” or will external users require access to the application’s functionality?

If you are building a distributed system for in-house use, you have a far greater chance of ensuring that each connected computer is running the same operating system, using the same programming framework (.NET, COM, J2EE, etc.), and you will be able to leverage your existing security system for purposes of authentication, authorization, and so forth. In this situation, you may be willing to select a particular distributed API that will tie you to a specific operating system/ programming framework for the purposes of performance.

867

868 CHAPTER 25 INTRODUCING WINDOWS COMMUNICATION FOUNDATION

In contrast, if you are building a system that must be reached by those outside of your walls, you have a whole other set of issues to contend with. First of all, you will most likely not be able to dictate to external users which operating system they make use of, which programming framework they use to build their software, or how they configure their security settings.

Furthermore, if you happen to work for a larger company or in a university setting that makes use of numerous operating systems and programming technologies, an in-house application suddenly faces the same challenges as an outward-facing application. In either of these cases, you need to limit yourself to a more flexible distributed API to ensure the furthest “reach” of your application.

Based on the answer to this key distributed computing question, the next task is to pinpoint exactly which API (or set of APIs) to make use of. By way of a painless overview, the following sections present a quick recap of some of the major distributed APIs historically used by Windows software developers. Once you finish this brief history lesson, you will easily be able to see the usefulness of Windows Communication Foundation.

Note Just to make sure we are all on the same page here, I feel compelled to point out that WCF (and the technologies it encompasses) has nothing to do with building an HTML-based web application. While it is true that web applications can be considered “distributed” in that two machines are typically involved in the exchange, WCF is about establishing connections to machines to share the functionality of remote components—not for displaying HTML in a web browser. Chapter 31 will begin your examination of building websites with the .NET platform.

The Role of DCOM

Prior to the release of the .NET platform, Distributed Component Object Model (DCOM) was the remoting API of choice for Microsoft-centric development endeavors. Using DCOM, it was possible to build distributed systems using COM objects, the system registry, and a good amount of elbow grease. One benefit of DCOM was that it allowed for location transparency of components. Simply put, this allowed client software to be programmed in such a way that the physical locations of the remote objects were not hard-coded. Regardless of whether the remote object was on the same machine or a secondary networked machine, the code base could remain neutral, as the actual location was recorded externally in the system registry.

While DCOM did enjoy some degree of success, for all practical purposes it was a Windowscentric API. Even though DCOM was ported to a few other operating systems, DCOM alone did not provide a fabric to build comprehensive solutions involving multiple operating systems (Windows, Unix, Mac) or promote sharing of data between diverse architectures (COM, J2EE, CORBA, etc.).

Note There were some attempts to port DCOM to run on various flavors of Unix/Linux, but the end result was lackluster and eventually became a technology footnote.

By and large, DCOM was best suited for in-house application development, as exposing COM types outside company walls entailed a set of additional complications (firewalls and so forth). With the release of the .NET platform, DCOM quickly became a legacy programming model, and unless you are maintaining legacy DCOM systems, you can consider it a deprecated technology.

The Role of COM+/Enterprise Services

DCOM alone did little more than define a way to establish a communication channel between two pieces of COM-based software. To fill in the missing pieces required for building a feature-rich

CHAPTER 25 INTRODUCING WINDOWS COMMUNICATION FOUNDATION

869

distributed computing solution, Microsoft eventually released Microsoft Transaction Server (MTS), which was subsequently renamed to COM+ at a later release.

Despite its name, COM+ is not only used by COM programmers—it is completely accessible to

.NET professionals. Since the first release of the .NET platform, the base class libraries provided a namespace named System.EnterpriseServices. Here, .NET programmers could build managed libraries that could be installed into the COM+ runtime in order to access the same set of services as a traditional COM+-aware COM server. In either case, once a COM+-aware library was installed into the COM+ runtime, it was termed a serviced component.

COM+ provides a number of features that serviced components can leverage, including transaction management, object lifetime management, pooling services, a role-based security system, a loosely coupled event model, and so on. This was a major benefit at the time, given that most distributed systems require the same set of services. Rather than forcing developers to code them by hand, COM+ provided an out-of-the-box solution.

One of the very compelling aspects of COM+ was the fact that all of these settings could be configured in a declarative manner using administrative tools. Thus, if you wished to ensure an object was monitored under a transactional context or belonged to a particular security role, you simply needed to select the correct check boxes.

While COM+/Enterprise Services is still in use today, this technology is a Windows-only solution that is best suited for in-house application development or as a back-end service indirectly manipulated by more agonistic front ends (e.g., a public website that makes calls on serviced components [aka COM+ objects] in the background).

Note WCF does not currently provide a way to build serviced components. However, it does provide a manner for WCF services to communicate with existing COM+ objects. If you need to build serviced components using C#, you will need to make direct use of the System.EnterpriseServices namespace. Consult the .NET Framework 3.5 SDK documentation for details.

The Role of MSMQ

The Microsoft Message Queuing (MSMQ) API allows developers to build distributed systems that need to ensure reliable delivery of message data on the network. As we all know too well, in any distributed system there is the risk that a network server is down, a database is offline, or connections are lost for mysterious reasons. Furthermore, a number of applications need to be constructed in such a way that they hold message data for delivery at a later time (known as queuing data).

At first, MSMQ was packaged as a set of low-level C-based APIs and COM objects. As well, using the System.Messaging namespace, .NET programmers could hook into MSMQ and build software that communicated with intermittently connected applications in a dependable fashion. Last but not least, the COM+ layer incorporated MSMQ functionality into the runtime (in a simplified format) using a technology termed Queued Components (QC).

Regardless of which programming model you used to interact with the MSMQ runtime, the end result ensured that applications could deliver messages in a reliable and timely fashion. Like COM+, MSMQ is still certainly part of the fabric of building distributed software on the Windows operating system.

The Role of .NET Remoting

As mentioned, with the release of the .NET platform, DCOM quickly became a legacy distributed API. In its place, the .NET base class libraries shipped with the .NET remoting layer, represented by the System.Runtime.Remoting namespaces. This API allows multiple computers to distribute objects, provided they are all running the applications under the .NET platform.

870 CHAPTER 25 INTRODUCING WINDOWS COMMUNICATION FOUNDATION

The .NET remoting APIs provided a number of very useful features. Most important was the use of XML-based configuration files to declaratively define the underlying plumbing used by the client and the server software. Using *.config files, it was very simple to radically alter the functionality of your distributed system simply by changing the content of the configuration files and restarting the application.

As well, given the fact that this API is useable only by .NET applications, you can gain various performance benefits, as data can be encoded in a compact binary format, and you can make use of the Common Type System (CTS) when defining parameters and return values. While it is possible to make use of .NET remoting to build distributed systems that span multiple operating systems (via Mono, briefly mentioned in Chapter 1 and detailed in Appendix B), interoperability between other programming architectures (such as J2EE) was still not directly possible.

Note Previous editions of this text included an entire chapter devoted to the topic of the .NET remoting APIs. With the release of WCF, however, I have decided not to include this chapter in this edition. The chapter on .NET remoting APIs (titled “The .NET Remoting Layer”) can be obtained free of charge from the Apress website (http://www.apress.com) by those who have purchased this text.

The Role of XML Web Services

Each of the previous distributed APIs provided little (if any) support to allow external callers to access the supplied functionality in an agnostic manner. When you need to expose the services of remote objects to any operating system and any programming model, XML web services provide the most straightforward way of doing so.

Unlike a traditional browser-based web application, a web service is simply a way to expose the functionality of remote components via standard web protocols. Since the initial release of .NET, programmers have been provided with superior support for building and consuming XML web services via the System.Web.Services namespace. In fact, in many cases, building a feature-com- plete web service is no more complicated than applying the [WebMethod] attribute to each public method you wish to provide access to. Furthermore, Visual Studio 2008 allows you to connect to a remote web service with the click of a button (or two).

Web services allow developers to build .NET assemblies containing types that can be accessed via simple HTTP. Furthermore, a web service encodes its data as simple XML. Given the fact that web services are based on open industry standards (HTTP, XML, SOAP, etc.) rather than proprietary type systems and proprietary wire formats (as is the case with DCOM or .NET remoting), they allow for a high degree of interoperability and data exchange. Figure 25-1 illustrates the agnostic nature of XML web services.

Of course, no distributed API is perfect. One potential drawback of web services is the fact that they can suffer from some performance issues (given the use of HTTP and XML data representation), and they may not be an ideal solution for in-house applications where a TCP-based protocol and binary formatting of data could be used without penalty.

A .NET Web Service Example

For many years now, .NET programmers have created web services using the ASP.NET Web Service project template of Visual Studio, which can be accessed using the File New Web Site dialog box. This particular project template creates a commonly used directory structure and a handful of initial files to represent the web service itself. While this project template is very helpful to get you up and running, you are able to build a .NET XML web service using a simple text editor and test it immediately using the ASP.NET development web server, WebDev.WebServer.exe (Chapter 31 examines this utility in more detail).

CHAPTER 25 INTRODUCING WINDOWS COMMUNICATION FOUNDATION

871

Figure 25-1. XML web services allow for a very high degree of interoperability.

By way of a quick example, assume you have authored the following programming logic in a new file named HelloWebService.asmx (*.asmx is the default file extension for a .NET XML web service file). Once you have done so, save it into C:\HelloWebService.

<%@ WebService Language="C#" Class="HelloWebService" %> using System;

using System.Web.Services;

public class HelloWebService

{

[WebMethod]

public string HelloWorld()

{

return "Hello World";

}

}

While this simple service is hardly doing anything terribly useful, notice that the file opens with the WebService directive, which is used to specify which .NET programming language is used in the file, and the name of the class type representing the service. Beyond this, the only point of interest is that the HelloWorld() method has been decorated with the [WebMethod] attribute. In many cases, this is all you need to do to expose a method to external callers via HTTP. Finally, notice that you do not need to do anything special to encode the return value into XML, as this is done automatically by the runtime.

If you wish to test this web service, simply open up a Visual Studio 2008 command prompt and enter the following command (if you’d like to see each option you can use with this development web server, simply enter the -? argument):

webdev.webserver /port:8080 /path:"C:\HelloWebService"