Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 112 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
112
Dung lượng
907,52 KB
Nội dung
BUILDING AND USING WCF SERVICES 913 of the service’s methods; instead of using the collections as its data source, the service will contact a database. In between sessions, you can persist t he collections to an XML file, as dis- cussed in Chapter 13, ‘‘XML in Modern Programming.’’ Start a fresh instance of Visual Studio and select File New New Project. Click WCF in the Installed Templates pane, and in the pane with the matching project types, select WCF Ser- vice Library. Name the new project WCFProducts and click OK to create the project. The new project that Visual Studio will create for you contains two files: the IService1.vb class, which is an interface that contains the signatures of the service methods, and the Service1.vb class, which contains the implementation of the methods. The methods are some extremely trivial sample methods and you can delete them right away. The first step is the design of a class that represents the entities our service knows about. Obviously, we need a Product and a Category class and I have nested the Category class within the Product class. Both classes contain just a few properties to identify products and categories. Add the Product class to the WCF project and insert in it the code of Listing 21.4. Listing 21.4: The Product.vb class <DataContract()> Public Class Product <DataMember()> Public ProductID As Integer <DataMember()> Public ProductName As String <DataMember()> Public ProductPrice As Decimal <DataMember()> Public ProductCategoryID As Integer Public Overrides Function ToString() As String Return ProductName & " (" & ProductID & ")" End Function <DataContract()> Public Class Category <DataMember()> Public CategoryID As Integer <DataMember()> Public CategoryName As String Public Overrides Function ToString() As String Return CategoryName & " (" & CategoryID.ToString & ")" End Function End Class End Class This is a very simple class that describes products and categories, if you ignore the deco- rations of the various members. The entire class is marked with the DataContract attribute, which tells the compiler that the following class contains the service’s contract: the entities our service knows about. The clients of the service will communicate with our class by submit- ting objects from the Product a nd Product.Category classes, and the service will return data to the client application using instances of these two classes. The DataMember attribute tells the compiler that the corresponding property is a member of the contract and that it should be exposed to the clients. If you have properties that you want to use in your code but not expose to clients, just don’t mark them with the DataMember attribute. 914 CHAPTER 21 BUILDING AND USING WEB SERVICES The next step is the definition of the methods that the clients will use to contact our ser- vice. The methods must be defined in an interface class, which contains the method definitions but not their actual implementation. This interface class contains the service’s metadata — the information required by a client to figure out the service’s capabilities. Add the IProduct class to the project and insert the statements shown in Listing 21.5 in it (the IProduct.vb file). Listing 21.5: Describing the Product class with an interface Imports System.ServiceModel <ServiceContract()> Public Interface IProduct <OperationContract()> Function GetAllCategories() As List(Of Product.Category) <OperationContract()> Function GetAllProducts() As List(Of Product) <OperationContract()> Function AddProduct(ByVal prod As Product) As Product <OperationContract()> Function RemoveProduct(ByVal ID As Integer) As Boolean <OperationContract()> Function GetCategoryProducts(ByVal ID As Integer) As List(Of Product) End Interface This is another trivial class, except that it’s marked with the ServiceContract attribute, which tells the compiler that the class contains the service’s operations (as opposed to the ser- vice’s data structure, which was defined in the Product class). The methods are also marked with the OperationContract attribute, which makes them available to clients. Without this attribute, the procedures would be internal methods and clients wouldn’t be able to see them. If the service exchanges simple data types with the client, this interface would be a dequate. However, practical services are not limited to simple data types like integers and strings. They communicate with the client using business objects, which are based on custom classes. These objects represent customers, products, invoices, and the like. If you want to make use of custom objects, you must declare them in a separate class like the Product class shown earlier. Finally, you must add yet another class to the project — this time a class that contains the actual code and implements the service. This is the ProductService class in the sample project, and its code is shown in Listing 21.6. The ProductService class implements the IProduct inter- face, taking into consideration the classes defined in the Product class. Listing 21.6: The implementation of the ProductService class <ServiceBehavior()> Public Class ProductService : Implements IProduct Shared _products As New List(Of Product) Shared _categories As New List(Of Product.Category) BUILDING AND USING WCF SERVICES 915 Public Function AddProduct(ByVal prod As Product) As Product Implements IProduct.AddProduct ‘ grab the next ID in _products list prod.ProductID = (From p In _products Select p.ProductID Order By ProductID Descending). FirstOrDefault + 1 ‘ If category field is not set to a valid category, ignore it If (From c In _categories Where c.CategoryID = prod.ProductCategoryID).Count = 0 Then prod.ProductCategoryID = Nothing End If products.Add(prod) Return prod End Function Public Function GetAllCategories() As System.Collections.Generic.List( Of Product.Category) Implements IProduct.GetAllCategories Return _categories End Function Public Function GetAllProducts() As System.Collections.Generic.List(Of Product) Implements IProduct.GetAllProducts Return _products End Function Public Function RemoveProduct(ByVal ID As Integer) As Boolean Implements IProduct.RemoveProduct products.Remove(_products.Find(Function(p) p.ProductID = ID)) End Function Protected Overrides Sub Finalize() MyBase.Finalize() End Sub Public Function GetCategoryProduct( ByVal categoryID As Integer) As List(Of Product) Implements IProduct.GetCategoryProducts Return (From p In _products Where p.ProductCategoryID = categoryID).ToList End Function Public Sub New() 916 CHAPTER 21 BUILDING AND USING WEB SERVICES _categories.Add(New Product.Category With {.CategoryID = 101, .CategoryName = "Electronics"}) _categories.Add(New Product.Category With {.CategoryID = 102, .CategoryName = "Cameras"}) _categories.Add(New Product.Category With {.CategoryID = 103, .CategoryName = "Software"}) End Sub End Class The data are stored in the _products and _categories collections, which are private to the class, and no client can manipulate these collections directly. This is the essence of the service: It allows clients to view and manipulate the data through a well-defined interface, and the ser- vice itself is in charge of maintaining the integrity of the data. Since we don’t have a database at the back end, we’re also responsible for maintaining the IDs of the various entities. Every time a new product is added, the code retrieves the largest product ID from the _products collection, adds 1 to it, and forms the ID of the new p roduct. The same is true for the IDs of the categories. Notice also that every time the service is initialized, it adds three rows to the _categories table. It goes without saying that you can change the implementation of the ser- vice so that it interacts directly with the Northwind database instead of custom collections. To do so, you will change the implementation of the ProductService class without having to touch the other two classes. As a consequence, client applications will continue using your service, but with the new implementation of the service, they will be seeing the data of the Northwind database. The two collections must be declared with the Shared keyword so that a ll instances of the service will see the same data. Had we declared the two collections with a Dim statement, a new set of collections would be created for each instance of the class invoked by a client. In other words, every client application would see its own data source. Your WCF service is ready to service clients. To test it, press F5 and you will see an icon in the lower-right corner of your screen informing you that the WcfSvcHost utility has started. This utility, which comes with Visual Studio, hosts the service and makes it available to clients at a specific IP address and port. Since WcfSvcHost is meant for testing purposes, only appli- cations running on the same machine can connect to it. Once the service has been debugged, it can be deployed as an IIS application. A few moments later you will see another window, the WCF Test Client utility, which allows you to test your new service without writing a client application. The first time you run the project you’ll see an error message to the effect that the service doesn’t expose any metadata. This happened because you haven’t configured your application yet. Right-click the App.config file in the Solution Explorer, and from the shortcut menu, select Edit WCF Configuration. The Configuration Editor window appears, as shown in Figure 21.11. Configuring WCF Services A WCF service is defined by three parameters: an address where it can be reached (the end- point), a binding protocol, and a contract. All three parameters are configurable, and you need not edit the service code to redeploy it or to support additional bindings. You only need to edit the configuration file. The address is an IP address or URL that specifies where the service is located. It’s the address of the machine on which the service is running and, consequently, the address to BUILDING AND USING WCF SERVICES 917 which clients must connect to make requests. The binding determines how the clients will talk to a service and WCF supports multiple bindings. The contract, finally, specifies what the service does; in other words, the methods it provides. The contract is the service interface, much like the classes and methods of a namespace. If you want to totally abstract a WCF service, think of it as a namespace that’s being hosted on a remote computer. Just as you can call a method in a namespace, you can call a method of a WCF service . As you saw in the first example of this chapter, you can access a remote service from within your project b y adding a reference to the service. With that reference in place, Visual Studio will take care of the housekeeping needed to connect to the remote service (what’s also known as the plumbing). Figure 21.11 The Configuration Edi- tor’s window allows you to configure the parame- ters of a WCF service. The binding tells the client how the messages will be transmitted between the client and the service. Web services use HTTP to exchange data with the clients. This, however, is not perfect for all cases. HTTP is a universal protocol, and it’s been implemented on every ope rating sys- tem, but it’s t he most generic protocol. Windows, as well as other operating systems, support messaging: a mechanism for reliably transmitting information between two computers, even if one of them is offline. When the receiving computer is connected, the message will be delivered and processed. This mechanism, which relies on Microsoft’s Message Queues, is the most reli- able mechanism for exchanging data between two computers, but this type of communication isn’t synchronous. There are situations where the WCF service and its client are deployed on the same local area network. For these cases, there are protocols, such as Named Pipes, that perform much faster than HTTP. I can’t discuss the merits of all available bindings in this chapter. This is an advanced topic, and the goal of this chapter is to introduce you to a technique for writing applications as services. The basic techniques are within the reach of the average VB devel- oper, and I will limit the discussion to the basic techniques for building WCF services and 918 CHAPTER 21 BUILDING AND USING WEB SERVICES deploying them on a web server. WCF allows you to build a service following the steps dis- cussed so far and then configure them. The configuration involves the specification of the end- point (the service’s address) and the binding protocol. You can even implement multiple bind- ings on the same service so that different clients can contact the same service using different protocols. To configure the sample WCF service, you must first change the name of the service. Although you changed the default name of the service, the configuration file still remembers the original name, Service1, which was the name of the sample class that was generated auto- matically and that we removed from the project. Click the WCFProducts.Se rvice1 item in the left pane of the Configuration Editor, which was shown in Figure 21.11, and then select the Name property in the right pane. Click the button with the ellipsis next to the service’s name and the Service Type Browser dialog box will open, as shown in Figure 21.12. This dialog box is similar to the Open dialog box, which allows you to select a file. Navigate to the project’s Bin/Debug folder and select the WCFProducts.dll file. Click open, or double-click the file’s name to see the names of all services implemented in the DLL. You will see a single service name, the WCFProducts.ProductService name. Select it and the close the dialog box by clicking the OK button. Figure 21.12 Configuring the name of the WCF service You will notice that the new service has two predefined endpoints. Click the first one and the endpoint’s properties will be displayed on the editor’s right pane. The first end- point uses the wsHttpBinding binding and implements the contract WCFProducts.Service1 service. There’s no Service1 service, so you must change the name of the service with the same process described earlier. Locate the project’s DLL and set the endpoint’s contract to WCFProducts.IProduct interface. While configuring the first endpoint, set its name to HTTPBinding. Now select the second endpoint and you’ll see that it implements the mexHttpBinding, as shown in Figure 21.13. This binding provides the service’s metadata and you need not change its settings. Just set its name to MEXBinding, so that it won’t be displayed as (Empty Name). BUILDING AND USING WCF SERVICES 919 Figure 21.13 Configuring an endpoint of a WCF service Save the configuration with the Save command from the File menu and close the Config- uration Editor. Now you’re ready to test the service. Press F5 again and this time the WCF Test Client window appears, as shown in Figure 21.14. The WCF Test Utility window con- sists of two panes: on the left pane you see all the methods of the service (you must expand the service’s interface to see the names of the methods), and on the right pane you can call the selected method and see the results. To see the categories shown in Figure 21.14, for example, I double-clicked the GetAllCategories item in the left pane and then I clicked the Invoke but- ton. The utility called the GetAllCategories method and displayed the results in the lower part of the pane. You can use the WCF Test Client utility to test the methods of your new service, but even- tually you must host your service to a web server, or an application, and call it from another Windows or web client. You can also test the methods that submit data to the service. If you double-click the AddProduct method name, a new tab will open in the right pane, as shown in Figure 21.15, and you’ll be prompted to enter values for the method parameters. Specify the parameter values (you don’t have to provide a value for the ProductID parameter; this value is assigned auto- matically by the service) and then click the Invoke button. The utility will call the AddProduct method, and if executed successfully, it will display the new product in the lower half of the tab, as shown in the figure. Note that the new product’s ID is included in the result of the method because the method returns an object of the Product type that represents the newly inserted row. Implementing a web or WCF service is no different from implementing a class that exposes certain functionality through a set of methods and communicates with another application by exchanging specific types. The only difference between a class you’d use in a Windows applica- tion and a service is that the members of the service are marked with special attributes. More- over, when it comes to WCF services, you must also configure them with the Configuration Editor. 920 CHAPTER 21 BUILDING AND USING WEB SERVICES Figure 21.14 Testing the methods of the new WCF service in the WCF Test Client utility Figure 21.15 Submitting a new product to the Product- Service service through the WCF Test Client ADO.NET Data Services Before ending this chapter, I’d like t o show you briefly how to create services that expose an entire database. This type of service comes as a special project component of Visual Studio, the ADO.NET Data Services component. An ADO.NET Data service is a web service that exposes an entire database, or part of it, as a web service. What’s special about this component is that it’s generated automatically for you; all you have to do is specify the tables you want to expose ADO.NET DATA SERVICES 921 and a wizard will generate the service for you. The data source can be a database, an Entity Data Model (EDM), or a collection of custom objects. There’s nothing new to learn and you can create and use data services immediately, with the exception of some t echniques for securing your data. The data service will expose methods to both query and update the data source, but you obviously don’t want to give access to your database to anyone on the Web. Let’s start the exploration of data services by building a new project, the DataService project; you can download it from this URL: www.sybex.com/go/masteringvb2010. Create a new pro- ject of the ASP.NET Web Site type, since your data will be exposed over HTTP. As you will see, you have no need for a website per se, just a web service that will expose the data of a specific database (or part of it). As soon as the project is created, delete the ASPX page that Visual Studio adds by default to any project of this type. First, you must create a data source. For the purpose of this example, you’ll expose data from the Northwind database, and to do so, you’ll create an ADO.NET Entity Data Model by adding a new component of this type to the project. Keep the default name, which is Model1.edmx. When the wizard starts, select all of the tables in the database, as you learned in Chapter 19. For this example, I’ve included all 12 tables of the Northwind database. I just dropped them on the EDM design surface and Visual Studio generated the Model1.edmx data model. Now that you have the data source, you can add an ADO.NET D ata Service component to your project to expose the selected tables through a web service. Right-click the project name and select Add New Item. When the Add New Item dialog box opens, select the ADO.NET Data Service. Name the new service NWWebDataService. Visual Studio will create the NWWebDataService.svc file for you and will open the new data service’s code window. You will see that the new class contains just a few lines of code: Imports System.Data.Services Imports System.Linq Imports System.ServiceModel.Web Public Class NWWebDataService ‘ TODO: replace [[class name]] with your data class name Inherits DataService(Of [[class name]]) ‘ This method is called only once to initialize service-wide policies. Public Shared Sub InitializeService( ByVal config As IDataServiceConfiguration) ‘ TODO: set rules to indicate which entity sets ‘ and service operations are visible, updatable, etc. ‘ Examples: ‘ config.SetEntitySetAccessRule("MyEntityset", EntitySetRights.AllRead) ‘ config.SetServiceOperationAccessRule( ‘ "MyServiceOperation", ServiceOperationRights.All) End Sub End Class The NWWebDataService inherits from another class, whose name you must supply by replacing class name in the code line that reads: Inherits DataService(Of [[class name]]). The class it derives from should be NorthwindEntities, which is the name of the 922 CHAPTER 21 BUILDING AND USING WEB SERVICES Data Entity class you created as the project’s data source. Technically, you didn’t specify the NorthwindEntities name, but Visual Studio created this class and named it after the database. The statements that are commented out specify the data you want to expose through your data service. By default, the data service won’t expose any data unless you tell it to do so. Replace the last two statements of the InitializeService routine with the following: config.SetEntitySetAccessRule("*", EntitySetRights.All) This statement instructs the service to expose all resources. Obviously, this is the last thing you want to do with a real service that will be accessed from outside your test machine, and I’ll come back to the issue o f security, but for now let’s grant unconditional access to all tables through your service. For the purpose of this chapter, the service will be hosted by the ASP.NET Development Server, which can be accessed from the same machine only. You’re probably thinking it’s time to add some real code, or look at a few thousand lines of code generated by the wizard. This isn’t the case; your data service is complete. Right-click the NWWebDataService component name, and from the context menu, select View In Browser. A few seconds later you will see a new Internet Explorer window displaying a list of all tables in the database, as shown in Figure 21.16. Figure 21.16 The service exposes the names of all tables in its data source. Each table, which is an EntitySet in the data source, is exposed as a collection. By appending the entity name to the base URL of t he service, you can view the rows in the corresponding tables. Change the URL in the browser address bar to any of the following to see the products, categories, and customers in the Northwind database: http://localhost:51000/NWWebDataService.svc/Products [...]... SSNs), and it must be declared as a two-dimensional array: Dim Persons (100 ,1) As String If you’d rather avoid the index 0, you can declare the two arrays as follows: Dim Names(1 To 11) As String Dim Persons(1 To 100 , 1 To 1) As String Chapter 3: Visual Basic Programming Essentials Use Visual Basic s flow-control statements Visual Basic provides several statements for controlling the flow of control in... Chapter 1: Getting Started with Visual Basic 2 010 Navigate the integrated development environment of Visual Studio To simplify the process of application development, Visual Studio provides an environment that’s common to all languages, known as an integrated development environment (IDE) The purpose of the IDE is to enable the developer to do as much as possible with visual tools before writing code... window Understand the basics of a Windows application A Windows application consists of a visual interface and code The visual interface is what users see at runtime: a form with controls with which the user can interact — by entering strings, checking or clearing check boxes, clicking buttons, and so on The visual interface of the application is designed with visual tools The visual elements incorporate... href="Order_Details(OrderID =105 01,ProductID=54)" /> ) but the gt operator The filtering expressions can get quite complicated because the URL syntax... following URL in your browser: http://localhost: 5100 0/NWWebDataService.svc/Customers(’ALFKI’)/Orders To isolate a specific column, append it to the table’s URL The following URL will return the city of the ALFKI customer: http://localhost: 5100 0/NWWebDataService.svc/Customers(’ALFKI’)/City The service will return it as an XML element: Berlin . new project, the DataService project; you can download it from this URL: www.sybex.com/go/masteringvb2 010. Create a new pro- ject of the ASP.NET Web Site type, since your data will be exposed. database: http://localhost: 5100 0/NWWebDataService.svc/Products ADO.NET DATA SERVICES 923 http://localhost: 5100 0/NWWebDataService.svc/Categories http://localhost: 5100 0/NWWebDataService.svc/Customers As. ?> - <feed xml:base=http://localhost: 5100 0/NWWebDataService.svc/ xmlns:d=http://schemas .microsoft. com/ado/2007/08/dataservices xmlns:m=http://schemas .microsoft. com/ado/2007/08/dataservices/metadata xmlns="http://www.w3.org/2005/Atom"> <title