Đang nạp dữ liệu ...
CMS - MENU
HỌC TẬP

Sửa thông tin bài viết Introduction Windows Communication Foundation Part4

17 Tháng Hai 2011 - vantheshark
Lượt xem: 1.802     Phản hồi: 0

Hosting the WCF Service


- Trong phần này chúng ta đã sẵn sàng mọi thứ để tạo một host cho service. Bản thân WCF service chỉ là một class library nên nó cần được thực thi bên trong một chương trình nào đó gọi là host. Trong thực tế, service có thể được host trong một Windows service hoặc trong một virtual directory của IIS. Nhưng trong phần này chúng ta sẽ tạo một host dạng console application tên là MagicEightBallServiceHost.



- Đầu tiên chúng ta tạo mới một project loại Console Application, thêm reference đến

System.ServiceModel.dll

MagicEightBallServiceLib

project ở phần trước, rồi thêm 2 namespace

System.ServiceModel

MagicEightBallServiceLib

vào file programe.cs như hình:



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using MagicEightBallServiceLib;

namespace MagicEightBallServiceHost
{

class Program
{

static void Main(string[] args)
{

Console.WriteLine("***** Console Based WCF Host *****");
Console.ReadLine();

}

}

}

Code 1: Code file program.cs

- Có một việc chúng ta phải quyết định trước khi build một host cho WCF service là nên chọn việc xác định những hosting logic bên trong code hay đưa chúng vào file config của chương trình. Như đã nói, điểm lợi ích của file config là bạn có thể thay đổi nhiều thứ mà không phải build và deploy lại chương trình. Lựa chọn thế nào là tùy ý người developer, trong ví dụ này chúng ta sẽ sử dụng file config. Vì vậy, bạn hãy thêm một file App.config vào project.

:bbpraroi:

Establishing the ABCs Within an App.config file


- Khi bạn build một host cho WCF service, bạn phải làm theo một số bước như sau, một số bước sẽ làm với file config và một số sẽ làm trong code:


  1. Xác định “endpoint” cho WCF service sắp được host bên trong file config.
  2. Bên trong code, sử dụng class “ServiceHost” để expose các service của bạn từ “endpoint” trên
  3. Đảm bảo rằng chương trình host của bạn lúc nào cũng chạy khi vẫn có những request từ client. Hiển nhiên, bước này không bắt buộc khi bạn đang host trong một window service hoặc trong IIS

- Trong WCF, thuật ngữ “endpoint” đơn giản chỉ tượng trưng cho ba thành phần là “address”, “binding” và “contract” mà chúng ta đã biết. Trong file XML config, một endpoint được thể hiện bên trong element <endpoint>, bên trong element này sẽ có các element con gồm address, binding và contract. Bây giờ bạn hãy update file config mới thêm vào lúc nãy bằng một endpoint như sau (trong ví dụ này chúng ta sử dụng port 8888):



<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="MagicEightBallServiceLib.MagicEightBallService">
<endpoint address="http://localhost:8080/MagicEightBallService"
binding="basicHttpBinding"
contract="MagicEightBallServiceLib.IEightBall"/>

</service>

</services>

</system.serviceModel>

</configuration>

Code 2: Xml endpoint bên trong file config

- Chú ý rằng element <system.serviceModel> là node root của tất cả các settings. Mỗi service exposed từ host của bạn sẽ được xác định bởi element <service> bên trong node <services>. Ở đây, element <service> có sử dụng một attribute tên là

name

(không bắt buộc) để xác định friendly name của service type.



- Node con <endpoint> chịu trách nhiệm xác định address, loại binding (ví dụ như basicHttpBinding trong ví dụ này), và tên đầy đủ của interface của WCF service contract (IEightBall). Bởi vì chúng ta đang dùng HTTP-based binding, nên scheme ở đây sẽ là

http://:bbpraroi:

Coding Agains the ServiceHost Type


- Sau khi đã có file config với các setting đầy đủ, những thứ còn lại cần code khá đơn giản. Khi chương trình chính chạy (console application host), chúng ta sẽ tạo một instance của ServiceHost. Lúc runtime, object này sẽ tự động đọc những thông tin trong file config và xác định đúng address, binding và contract tương ứng:



static void Main(string[] args)
{

Console.WriteLine("***** Console Based WCF Host *****");
using (ServiceHost serviceHost = new ServiceHost(typeof(MagicEightBallService)))
{

// Open the host and start listening for incoming messages.
serviceHost.Open();
// Keep the service running until the Enter key is pressed.
Console.WriteLine("The service is ready.");
Console.WriteLine("Press the Enter key to terminate service.");
Console.ReadLine();

}

}

Code 3: Đoạn code để khai báo một instance ServiceHost object

- Nếu bây giờ bạn run application, bạn sẽ thấy hình như sau, service của bạn đã sẵn sàng để nhận các request từ phía clients (mặc dù chúng ta chưa làm tới chương trình client nào... hê hê

:bbpcuoi3:

)





***** Console Based WCF Host *****
The service is ready.
Press the Enter key to terminate service.

Hình 1: Service host đã sẵn sàng cho các external request qua HTTP binding

Host Coding Options


- Ở code trên, chúng ta đang tạo ServiceHost bằng constructor chỉ với tên của service type. Tuy nhiên, ta có thể sử dụng constructor khác với các thông tin về các addresses mà service có thể được access. Lúc này, giá trị của address được xác định trong file config; ta có thể sử dụng cách sau để làm tất cả trong code, dân gian còn gọi là hard-code

:bbpcuoi3:

using (ServiceHost serviceHost = new ServiceHost(typeof(MagicEightBallService),
new Uri[]{new Uri("http://localhost:8080/MagicEightBallService")}))
{
...
}

Code 4: Hard-code một endpoint trong code

- Một trong những điều phiền phức nho nhỏ khi chọn cách sử dụng file config là …có nhiều cách để config, tùy thuộc vào lượng thông tin bạn hard-code. Bạn hãy xem ví dụ sau:



<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="MagicEightBallServiceLib.MagicEightBallService">
<!-- Address obtained from <baseAddresses> -->
<endpoint address="" binding="basicHttpBinding"
contract="MagicEightBallServiceLib.IEightBall"/>
<!-- List all of the base addresses in a dedicated section-->
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/MagicEightBallService"/>

</baseAddresses>

</host>

</service>

</services>

</system.serviceModel>

</configuration>

Code 5: Config file XML theo nhiều cách

- Trong trường hợp này, attribute “address” của element “endpoint” giữ giá trị rỗng, và cho dù bạn không hard-code address Uri khi tạo instance ServiceHost đi nữa, chương trình host vẫn chạy như trước vì giá trị address sẽ được lấy từ “baseAddress”. Cách lưu trữ những address trong <baseAddresses> có nhiều điểm thuận lợi, đó là có thể một số phần khác của file config sẽ cần sử dụng đến giá trị address, nên để nó riêng một chỗ ta có thể sử dụng ở nhiều nơi. Vì thế, thay vì phải copy và paste các giá trị adddress vào trong một file config, bạn có thể để riêng giá trị này như trên.



* Ở những ví dụ sau, chúng ta sẽ được giới thiệu một tool để thay đổi những config này dễ dàng hơn

- Trước khi chúng ta build một client application để giao tiếp với service, chúng ta hãy tìm hiểu thêm vai trò của lớp ServiceHost, element <service.serviceModel> cũng như vai trò của metadata exchange (MEX) services.



Details of the ServiceHost Type


- Lớp ServiceHost được sử dụng để config và expose một WCF service từ chương trình host. Tuy nhiên, chúng ta chỉ nên sử dụng lớp này nếu cần trực tiếp sử dụng nó để build một chương trình đặc biệt để host các services. Nếu bạn sử dụng IIS (trong Vista là WAS) để expose service, object ServiceHost sẽ được tạo tự động thay cho bạn.

:bbpraroi:

- Như bạn thấy, lớp này đòi hỏi một service description từ file config. Những thông tin này có thể được đọc tự động trong quá trình tạo object, nó cũng có thể được config bằng một số members. Ngoài method Open() và Close(), bảng dưới đây sẽ liệt kê một số members khác của lớp này:



Bảng 1: Select Members of the ServiceHost Type




Members Ý nghĩa
Authorization Property này dùng để lấy authentication level của service
AddServiceEndpoint() Method này dùng để đăng kí một endpoint cho chương trình host
BaseAddresses Trả về một list các baseAddresses của service hiện tại
BeginOpen()
BeginClose()
Method này cho phép bạn đóng và mở một ServiceHost object theo cách bất đồng bộ
CloseTimeout Property này dùng đế set và get thời gian cho phép để close 1 Service
Credentials Property này dùng lấy giá trị security credentials đang sử dụng bởi service hiện tại
EndOpen()
EndClose()
Property này dùng kết hợp với BeginOpen và BeginClose
OpenTimeout Property này dùng để set và get thời gian tối đa để một service start up
State Property này dùng để lấy trạng thái của communication object


Details of the <system.serviceModel> Element


- Tương tự như một XML element bất kì, <system.serviceModel> có thể chứa một số element con với nhiều attributes khác nhau. Bạn có thể tham khảo .NET Framework 3.5 SDK để tìm hiểu chi tiết các attributes này, còn sau đây là bộ khung những sub elements:



<system.serviceModel>
<behaviors>
</behaviors>
<client>
</client>
<commonBehaviors>
</commonBehaviors>
<diagnostics>
</diagnostics>
<serviceHostingEnvironment>
</serviceHostingEnvironment>
<comContracts>
</comContracts>
<services>
</services>
<bindings>
</bindings>

</system.serviceModel>

Code 6: Các sub elements của <system.serviceModel>

Bảng sau đây sẽ mô tả ý nghĩa của các element này:



Bảng 2: SubElements of <service.serviceModel>



SubElement Ý nghĩa
behaviors WCF hỗ trợ nhiều endpoints và service behaviors. Behavỉors cho phép bạn customize những chức năng của host và client
bindings Element này cho phép bạn xác định các loại binding cho host
client Element này chứa danh sách các endpoints được sử dụng bởi client để connect đến service
comContracts Element này định nghĩa một COM contract cho phép WCF và COM có thể giáo tiếp với nhau
commonBehaviors Element này chỉ được set bên trong một machine.config, nó có thể được dùng để xác định tất cả behaviors được sử dụng bởi các WCF service trên một machine
diagnostics Element này chứa những setting cho các diagnostic features của WCF, user có thể enable/disable tracking, performance counters, và WMI provider, và có thể thêm những custom message filters
serviceHostingEnvironment Element này được dùng để xác định xem một operation có phải là một initial operation trong một session hay không
services Element này chứa các WCF services exposed từ chương trình host


Enabling Metadata Exchange


- Một WCF client application sẽ giao tiếp với WCF service nhờ vào một lớp proxy được sinh ra tự động. Bạn có thể tự tạo ra lớp proxy này nhưng không nên mất công làm chi, nhất là có thể sinh ra rất nhiều lỗi. Có một tool để sinh ra mọi thứ cho bạn, kể cả file config cho client application: svcutil.exe. Đó là một command line tool mà bạn có thể dùng lệnh console để sử dụng, còn trong VS.NET 2008, bạn có thể làm tương tự bằng cách chọn Menu Project rồi chọn Add Service Reference option.



- Tuy nhiên, để những tool này có thể sinh ra proxy code cũng như file config, chúng phải biết được format của WCF service interfaces và các data contracts.



- Metadata exchange (MEX) là một WCF “service behavior” có thể được dùng để thay đổi và điều chỉnh cách WCF runtime “handle” service của bạn. Mỗi <behavior> element có thể định nghĩa một số những activities mà service có thể thực hiện. WCF cung cấp sẵn một số behavior và bạn cũng có thể tự build những behavior của mình.



- MEX behavior (mặc định sẽ bị disabled) sẽ chặn các request được gửi qua HTTP GET. Do đó nếu bạn muốn svcutil.exe hay VS.NET 2008 có thể sinh các proxy code và file config, bạn phải enable nó lên.



- Có thể enable MEX bằng cách thêm vào một số setting trong file config. Đầu tiên, bạn phải thêm một node <endpoint> cho MEX setting. Sau đó, bạn phải định nghĩa một WCF behavior để cho phép HTTP GET access. Tiếp đó, bạn cần kết hợp behavior này với service của bạn thông qua “behaviorConfiguration” element. Cuối cùng, bạn cần thêm một node <host> để định nghĩa base addess cho service này (MEX sẽ dựa vào đây để xác định location của types được mô tả).



* Bước này có thể được bỏ qua nếu bạn sử dụng một System.Uri object để thay cho base address trong trường hợp này.

- Đoạn config sample dưới đây sẽ tạo một custom <behavior> element tên là

EightBallMEXBehavior

tương ứng với service:



<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="MagicEightBallServiceLib.MagicEightBallService" behaviorConfiguration="EightBallServiceMEXBehavior">
<endpoint address="" binding="basicHttpBinding" contract="MagicEightBallServiceLib.IEightBall"/>
<!-- Enable the MEX endpoint -->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<!-- Need to add this so MEX knows the address of our service -->
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/MagicEightBallService"/>

</baseAddresses>

</host>

</service>

</services>
<!-- A behavior definition for MEX -->
<behaviors>
<serviceBehaviors>
<behavior name="EightBallServiceMEXBehavior" >
<serviceMetadata httpGetEnabled="true" />

</behavior>

</serviceBehaviors>

</behaviors>

</system.serviceModel>

</configuration>

Code 7: Một MEX config sample

- Bây giờ bạn có thể restart service và xem metadata description bằng một web browser bất kì ở địa chỉ sau đây:


http://localhost:8888/MagicEightBallService


- Khi bạn mở homepage của WCF này, bạn được cung cấp những chi tiết kĩ thuật về cách sử dụng service cũng như cách xem WSDL contract, v.v.

:bbpraroi:

WCF service homepage

Hình 2: WCF service homepage
Các bạn đang xem bài viết về Introduction WCF từ blog của Nguyễn Thoại (http://nthoai.blogspot.com)


Building the WCF Client Application


- Chương trình host service đã chạy ngon lành, công việc cuối cùng là build một chương trình client để thử service của chúng ta. Như đã giới thiệu, .NET Framework 3.5 SDK hỗ trợ một vài cách để generate proxy code và file config cho client application. Để bắt đầu, hãy tạo một console application tên là MagicEightBallServiceClient.

:bbpraroi:

Generating Proxy Code Using svcutil.exe



- Cách đầu tiên để build một client side proxy là sử dụng tool svcutil.exe. Sử dụng tool này, bạn có thể generate một file C# proxy code và một file config tương ứng cho client application. Trước hết bạn cần phải xác định được service’s endpoint. Parameter /out: của tool này được dùng để xác định tên file proxy C# được sinh ra, và /config: để xác định tên file config.



- Hãy chạy chương trình service host, rồi đánh lệnh sau đây trong VS.NET 2008 conmmand prompt, nó sẽ generate 2 files trong thư mục hiện hành:



svcutil http://localhost:8888/MagicEightBallService /out:myProxy.cs /config:app.config

- Nếu mở file myProxy.cs, bạn sẽ thấy một client side code thể hiện interface IEightBall và một class mới EightBallClient, đó chính là lớp proxy. Class này derives từ một generic class,

System.ServiceMode.ClientBase

<T>, T chính là serviceType interface.



- Ngoài một số constructors, bạn sẽ thấy các method được đánh dấu bằng attribute [OperationContract](trong service contract) thì ở đây sẽ có một method tương ứng, trong đó property Channels của parrent class sẽ được dùng để invoke chính xác method của service. Sau đây là một phần code của proxy type được sinh ra:



[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public partial class EightBallClient : System.ServiceModel.ClientBase<IEightBall>, IEightBall
{

...
public string ObtainAnswerToQuestion(string userQuestion)
{

return base.Channel.ObtainAnswerToQuestion(userQuestion);

}

}

Code 8: Partial snapshot of the proxy type

- Khi bạn tạo một instance của proxy type để sử dụng, base class của nó sẽ tự động thiết lập một connection đến endpoint dựa trên những settings trong client site config. Cũng giống như file config ở phía server, file config phía client cũng chứa một <endpoint> element và những chi tiết mà basicHttpBinding sử dụng để giao tiếp với service.



- Thêm vào đó, bạn sẽ thấy một <client> element, node này cũng tương tự như phía server sẽ thiết lập các ABCs cho phía client



<client>
<endpoint
address="http://localhost:8080/MagicEightBallService"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IEightBall"
contract="ServiceReference.IEightBall"
name="BasicHttpBinding_IEightBall" />

</client>

Code 9: Một XML config phía client

- Bây giờ, bạn có thể include 2 file mới được sinh ra vào client project (nhớ add reference đến

System.ServiceModel.dll

) và sử dụng proxy type để giao tiếp với remote WCF service. Tuy nhiên, hãy tạm hoãn việc đó, chúng ta hãy xem VS.NET sinh các file cho phía client như thế nào

:bbpcuoi3:

Generating Proxy Code Using Visual Studio 2008


- Nếu không muốn sử dụng svcutil.exe tool, bạn có thể sinh các client code bằng VS.NET 2008 bằng cách chọn option Add Service Reference từ menu Project. Khi activate menu này xong, bạn sẽ bị yêu cầu nhập vào server URI:



Generating the proxy files using Visual Studio 2008

Hình 3: Generating the proxy files using Visual Studio 2008

- Không chỉ tạo và tự động insert những proxy files vào project hiện tại cho bạn, tool này còn tự thêm những reference đến các WCF assemblies. Proxy class khi được sinh ra từ tool này sẽ tự động được định nghĩa trong namespace ServiceReference, là nested namespace trong client’s namespace. Sau đây là code của client:



// Location of the proxy.
using MagicEightBallServiceClient.ServiceReference;
namespace MagicEightBallServiceClient
{

class Program
{

static void Main(string[] args)
{

Console.WriteLine("***** Ask the Magic 8 Ball *****\n");
using (EightBallClient ball = new EightBallClient())
{

Console.Write("Your question: ");
string question = Console.ReadLine();
string answer = ball.ObtainAnswerToQuestion(question);
Console.WriteLine("8-Ball says: {0}", answer);

}
Console.ReadLine();

}

}

}

Code 10: Code C# của chương trình Client

- Bây giờ nếu chương trình service host vẫn đang chạy, bạn hãy run chương trình client và sẽ thấy kết quả trên màn hình:





***** Ask the Magic 8 Ball *****
Your question: Will I get this book done soon
8-Ball says: Will I get this bok done soon? No.

Hình 4: Kết quả chạy chương trình client
Các bạn đang xem bài viết về Introduction WCF từ blog của Nguyễn Thoại (http://nthoai.blogspot.com)


Configuring a TCP-Based Binding


- Trong ví dụ trên, cả client và server đều được config để sử dụng loại binding đơn giản nhất là

HTTP-based bindings

, basicHttpBinding. Bởi vì những setting này đều được đặt trong file config nên ta có thể dễ dàng thay đổi sang loại binding khác. Bạn hãy thử copy các chương trình chạy của client và server sang các thư mục khác, sau đó lần lượt sửa đổi 2 file config sang netTcpBinding rồi chạy thử để thấy kết quả.

:bbpnodo:

Using the WCF Service Library Project Template


- Trong phần này, chúng ta sẽ tìm hiểu một số chủ đề khác không kém quan trọng, bao gồm lợi ích của WCF service library project template, chương trình WCF Test Client, tool WCF configuration editor, host một WCF services bên trong một Windows service và call service theo kiểu bất đồng bộ (asynchronous).



Building a Simple Math Service


- Trước hết, hãy tạo một project mới dạng WCF Service Library tên là

MathServiceLibrary

. Sau đó đổi tên file IService1.cs thành IBasicMath.cs. Sau đó xoá tất cả code sinh tự động và thay bằng đoạn code như sau:



namespace MathServiceLibrary
{

[ServiceContract(Namespace="www.Intertech.com")]
public interface IBasicMath
{

[OperationContract]
int Add(int x, int y);

}

}

Code 11: interface IBasicMath

- Kế tiếp, đổi tên Service1.cs thành MathService.cs, và thay thế code sinh tự động bằng đoạn code dưới đây:



namespace MathServiceLibrary
{

public class MathService : IBasicMath
{

public int Add(int x, int y)
{

// To simulate a lengthy request.
System.Threading.Thread.Sleep(5000);
return x + y;

}

}

}

Code 12: class MathService

- Cuối cùng, hãy mở file App.config và replace những nơi xuất hiện IService1 bằng IBasicMath, Service1 bằng MathService. Nếu để ý bạn sẽ thấy rằng file config này đã tự động enable MEX và sử dụng wsHttpBinding.

:bbpraroi:

Testing the WCF Service with WcfTestClient.exe



- Một điểm thuận lợi của WCF Service Library project là khi bạn debug hay run library này, nó sẽ tự động đọc file config và từ đó load một WCF Test Client application (WcfTestClient.exe). Chương trình này cho phép bạn từng method của service interface như khi bạn build một WCF service và rõ ràng bạn không phải mất công sức để build các chương trình host/client chỉ để test.

:bbpraroi:

- Hình bên dưới mô tả môi trường test của MathService. Chú ý là khi bạn double click lên một interface method, bạn có thể nhập vào các giá trị input rồi invoke method đó.



- Không chỉ dùng để test các service library của bạn, tool này còn có thể dùng để test bất kì một WCF service nào khi bạn chạy nó trong command line với một MEX endpoint. Ví dụ, bạn có thể test service MagicEightBallService bằng command sau đây (mở bằng Visual Studio 2008 command prompt):



wcftestclient http://localhost:8888/MagicEightBallService


Testing the WCF service using WcfTestClient.exe

Hình 5: Testing the WCF service using WcfTestClient.exe

Altering Configuration Files Using SvcConfigEditor.exe



- Một lợi ích nữa khi sử dụng WCF Service Library project là bạn có thể right-click lên App.config trong Solution Explorer và activate tool Service Configuration Editor, SvcConfigEditor.exe.



Start chương trình config editor

Hình 6: Start chương trình config editor
Các bạn đang xem bài viết về Introduction WCF từ blog của Nguyễn Thoại (http://nthoai.blogspot.com)


- Khi bạn chạy tool này, bạn có thể thay đổi những setting trong file XML config dễ dàng hơn nhiều. Có nhiều điểm thuận lợi khi sử dụng tool này hơn so với tự tay thay đổi file config. Bạn có thể tin chắc rằng những code setting sinh ra bởi tool này sẽ đúng format và định dạng như mong muốn. Kế đến, bạn sẽ dễ dàng thấy được giá trị chính xác của một values nào đó được gán vào một attribute tương ứng. Điều hay nhất là bạn không cần phải làm mọi thứ trên bằng tay.

:bbpraroi:

Giao diện chương trình config editor

Hình 7: Giao diện chương trình config editor


Code sample :

Download


Tham khảo:


http://msdn.microsoft.com/en-us/magazine/cc163647.aspx


BÌNH LUẬN:
Copyright © by ASP.NET VIETNAM
Contact us: ngothanhtung.it@gmail.com