Thoại đã trở lại, lợi hại gấp nhiều lần
Posted On Saturday, February 12, 2011 at at 3:16 PM by UnknownHai năm gần đây mình không viết bài nào vì dành nhiều thời gian cho những quyết định lớn chẳng hạn như .... cưới vợ. Hiện nay tình hình đã tạm ổn định, tổng thống Ai Cập đã chính thức từ chức, ngoài ra mình đã có công việc tốt nên sẽ quay lại thói quen viết blog. Tuy nhiên, những bài blog từ hôm nay sẽ không dài dòng hoặc mang tính giới thiệu kĩ thuật như trước mà sẽ là những bài ngắn gọn hơn và chỉ nói về problem và solution, tất nhiên là những problem mình gặp phải trong công việc hằng ngày. Và một điều khác nữa là mình sẽ viết bằng tiếng Anh thay vì tiếng Việt, mục đích để hướng đến nhiều người đọc hơn, cho nên bài viết này có thể là bài viết tiếng Việt sau cùng trên blog cá nhân của mình, những bài viết về sau sẽ được post ở http://thoai-nguyen.blogspot.com. Các bài tiếng Việt sẽ được post ở trang kucku.vn. Đây là bài viết đầu tiên cho năm mới 2011 :D MVC Test Controller Builder và NSubstitute
Nhân tiện, mình xin giới thiệu về công ty hiện tại của mình. Minh đang giữ vị trí lập trình viên ở công ty Community Engine tại phía bắc Sydney. Community Engine team là một team tuyệt vời nhất mà mình từng có cơ hội tham gia. Community Engine đang build một web platform để host các website của khách hàng, platform này sử dụng các công nghệ mới nhất của Microsoft như ASP.NET MVC, Entity Framework 4.0. Platform này còn sử dụng MongoDB cho các social features như FourSquare và SourceForge cùng với Solr cho các chức năng Search và Redis cho distributed caching. Vậy nếu bạn đang ở Sydney hoặc muốn sắp tới Sydney, bạn muốn tìm một công việc .NET ưng ý hãy soạn lại CV và gửi cho mình hoặc gửi cho Community Engine nhưng nhớ nhắc đến blog của mình trong hồ sơ của bạn. Community Engine là một công ty tuyệt vời với rát nhiều nhân viên đến từ nhiều nơi trên thế giới như England, Australia, France, India, Egypt, China, Iran, Vietnam, ... và lúc nào cũng cần các vị trí Team Leader, Mid/Senior Dot net dev, và các vị trí sau đây:
- Digital BDM
- Front end / UX developers
- Junior Project Manager
- Digital Project Manager
- Customer Support Officer
- Web Business Analyst
- System Administrator
- Tech Writer
- Test Analyst
Thoại
NHibernate : Some Naked Thoughts
Posted On Thursday, June 18, 2009 at at 4:09 PM by Unknownhttp://codebetter.com/blogs/karlseguin/archive/2009/06/10/nhibernate-some-naked-thoughts.aspx
By Karl Seguin
Roland Weigelt's G h o s t D o c
Posted On Friday, February 27, 2009 at at 10:06 AM by UnknownCode của bạn thường thiếu comment:
12 public partial class Main : Form
13 {
14 public Main()
15 {
16 InitializeComponent();
17 }
18
19
20
21
22 private void buttonCommand_Click(object sender, EventArgs e)
23 {
24 this.txtResult.Text = "";
25 this.lblFindResult.Text = "";
26 System.Nullable<System.Guid> personId = null;
27 System.Nullable<System.Guid> surveyID = null;
Chỉ việc sử dụng Ghost Doc:
Code sẽ thành thế này
12 public partial class Main : Form
13 {
14 public Main()
15 {
16 InitializeComponent();
17 }
18
19
20
21
22 /// <summary>
23 /// Handles the Click event of the buttonCommand control.
24 /// </summary>
25 /// <param name="sender">The source of the event.</param>
26 /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
27 private void buttonCommand_Click(object sender, EventArgs e)
28 {
29 this.txtResult.Text = "";
30 this.lblFindResult.Text = "";
31 System.Nullable<System.Guid> personId = null;
32 System.Nullable<System.Guid> surveyID = null;
Download ở đây: http://www.roland-weigelt.de/ghostdoc/
Introduction Windows Communication Foundation Part5 (Last)
Posted On Tuesday, February 24, 2009 at at 5:10 PM by UnknownBài viết này được dịch từ Chapter 25 - INTRODUCING WINDOWS COMMUNICATION FOUNDATION của sách Pro C# 2008 and the NET 3.5 Platform Fourth Edition.
Hosting the WCF Service As a Windows Service
- Cũng dễ dàng nhận thấy rằng nếu host một WCF service trong một Console application hay trong một GUI desktop application không thích hợp lắm trong môi trường server bởi vì người ta thường muốn chương trình host phải chạy liên tục ở backgroud và luôn available cho các client request. Bởi vậy dù bạn vẫn có thể minimize host application xuống taskbar, nhưng vẫn có khả năng bạn sẽ vô tình shutdown chương trình host dẫn đến mọi kết nối của client sẽ bị đứt.
* Tuy ta có thể làm một chương trình desktop application chạy bình thường mà không cần main Windows, nhưng nó vẫn cần phải được execute bởi một người nào đó khi login vào Windows. Trong khi đó Windows service có thể start dễ dàng mà không cần ai login vào Windows.
- Một đặc điểm dễ thấy nhất của Windows service là nó có thể start ngay sau khi machine vừa khởi động. Ngoài ra như đã nói, một Windows service có thể chạy ngầm dưới background và không cần đến một tương tác nào của người dùng Windows.
- Chúng ta sẽ thử build một service như vậy bằng cách sử dụng Windows service project template. Ta hãy tạo một project dạng Windows service tên là MathWindowsServiceHost (Hình 1). Sau đó hãy đổi tên Service1.cs thành MathWinService.cs
Hình 1: Creating a Windows service to host our WCF service
Specifying the ABCs in Code
- Tương tự như những lần trước, ta cũng add reference tới những assembly như System.ServiceModel.dll và project MathServiceLibrary. Chúng ta cần tạo ra một ServiceHost bên trong function OnStart() như sau:
{
// A member variable of type ServiceHost.
private ServiceHost myHost;
public MathWinService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
// Just to be really safe.
if (myHost != null)
{
myHost.Close();
myHost = null;
}
Uri address = new Uri("http://localhost:8888/MathServiceLibrary");
// Create the host.
myHost = new ServiceHost(typeof(MathService), address);
WSHttpBinding binding = new WSHttpBinding();
Type contract = typeof(IBasicMath);
// Add this endpoint.
myHost.AddServiceEndpoint(contract, binding, address);
AddMexEndpoint(myHost);
// Open the host.
myHost.Open();
}
protected void AddMexEndpoint(ServiceHost myHost)
{
ServiceMetadataBehavior smb = myHost.Description.Behaviors.Find<ServiceMetadataBehavior>();
// If not, add one
if (smb == null)
smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
myHost.Description.Behaviors.Add(smb);
// Add MEX endpoint
myHost.AddServiceEndpoint(
ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexHttpBinding(),
"mex"
);
}
protected override void OnStop()
{
// Shut down the host.
if (myHost != null)
myHost.Close();
}
}
Code 1: Code method OnStart
- Đoạn code ở trên chỉ thể hiện cách build một service host từ code, bạn hoàn toàn có thể sử dụng file config để làm tất cả những việc này.
Enabling MEX
- Chúng ta cũng có thể enable MEX từ code như trên (Trong code sample bên dưới có implement MEX endpoint). Nhưng dễ dàng nhất là thêm một file App.config vào Windows service project như sau:
<configuration>
<endpoint address="mex"
contract="IMetadataExchange" />
<!-- Need to add this so MEX knows the address of our service -->
<host>
</baseAddresses>
</host>
</service>
</services>
<!-- A behavior definition for MEX -->
<behaviors>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Code 2: MEX settings
Creating a Windows Service Installer
- Một Windows service khi install thì sẽ được đăng kí vào hệ điều hành. Do đó, bạn cần phải tạo một project installer cho nó. Project installer này sẽ chứa những phần code cần thiết để bạn đăng kí service này vào hệ thống. Để tạo ra một installer, bạn right-click lên màn hình design của MathWinService và chọn “Add Installer” (Hình 2)
Hình 2: Thêm installer cho Windows service
- Sau khi chọn “Add Installer”, bạn sẽ thấy có hai components được thêm vào màn hình designer. Thành phần đầu tiên (mặc định được đặt tên là serviceProcessInstaller1) sẽ được dùng để install một service mới vào hệ thống. Bạn hãy chọn nó, và sử dụng cửa sổ Properties để set property “Account” thành “LocalSystem”
- Thành phần thứ hai (mặc định được đặt tên là serviceInstaller1) sẽ thực sự install service của bạn. Tương tự, hãy sử dụng cửa sổ Properties, đổi “ServiceName” thành “Math Order Service” (Đây là một friendly name của service khi đăng kí vào hệ thống, bạn sẽ thấy nó trong chương trình services.msc của Windows), sau đó set “StartType” thành “Automatic”, bạn cũng có thể set giá trị cho Description nếu muốn. Sau cùng, hãy build lại project.
Installing the Windows Service
- Một Windows service có thể được install bằng một chương trình setup quen thuộc (như một file msi installer) hoặc bằng chương trình installutil.exe command-line tool. Nếu bạn muốn sử dụng cách thứ 2, hãy dùng Visual Studio 2008 command prompt, đổi thư mục hiện hành vô \bin\Debug trong project MathWindowsServiceHost. Và gõ lệnh sau đây:
installUtil MathWindowsServiceHost.exe
- Nếu như install thành công, bạn sẽ thấy friendly name của Windows service này hiển thị bên trong Services list của hệ thống. Bạn có thể mở chương trình này trong Administrator Tools (bên trong Control Panel) hoặc sử dụng lệnh services.msc /s
Hình 3: Xem windows service của bạn sau khi đã install vào hệ thống
- Bây giờ service của bạn đã chạy, bạn có thể build một client application để gọi thử service này. Nếu nó chưa chạy (như hình trên là chưa chạy), bạn hãy start nó.
Invoking a Service Asynchronously
- Bạn hãy tạo một Console Application và đặt tên là MathClient. Sau đó add Service Reference đến Windows service vừa nãy. Nhưng đừng có click button OK vội mà hãy click vào button “Advanced…” như trong hình dưới đây:
Hình 4: Reference our MathService
- Khi click button “Advanced”, bạn sẽ thấy những configuration khác cho proxy. Ta có thể chọn để generate code để có thể call những “remote methods” asynchronous (bất đồng bộ, gọi xong không phải chờ mà có thể thực hiện những dòng lệnh khác, khi nào remote method trả kết quả về sẽ có nơi để nhận và xử lý kết quả đó) bằng cách check vào “Generate Asynchoronous Operators”.
- Có một option khác trong dialog box này đáng quan tâm là Add Web Reference. Nếu bạn đã từng sử dụng XML webservice trong VS.NET 2005 hay trước đó, bạn có thể thấy Add Web Reference thay vì Add Service Reference. Nếu bạn click vào button này, proxy code sẽ được generate theo kiểu cũ để có thể gọi những web service *.asmx.
- Những option khác được sử dụng để control quá trình generate các data contracts mà ta sẽ bàn tới sau. Bạn hãy chọn “Generate Asynchronous Operators” rồi click OK để quay về Visual Studio IDE.
Hình 5: Advanced client-side proxy configuration options
- Lúc này, proxy code sẽ chứa những methods giúp bạn gọi các members của service contract bằng cách sử dụng Begin/End asynchoronous invocation pattern. Sau đây là code sample :
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("***** The Async Math Client *****\n");
using (BasicMathClient proxy = new BasicMathClient())
{
proxy.Open();
// Add numbers in an async manner, using a lambda expression.
IAsyncResult result = proxy.BeginAdd(2, 3,
ar =>
{
Console.WriteLine("2 + 5 = {0}", proxy.EndAdd(ar));
}, null);
while (!result.IsCompleted)
{
Thread.Sleep(200);
Console.WriteLine("Client working...");
}
}
Console.ReadLine();
}
}
}
Code 3: Gọi remote methods asynchoronous
Designing WCF Data Contracts
- Ở phần cuối này chúng ta sẽ tìm hiểu thêm về Data Contracts. WCF services trước bao gồm một method rất đơn giản và chỉ sử dụng các type built-in của CLR. Khi bạn sử dụng bất kì web-service binding types (basicHttpBindings, wsHttpinding, …), dữ liệu vào và ra được tự động format thành XML elements nhờ vào System.Runtime.Serialization.XmlFormatter trong assembly System.Runtime.Serialization.dll. Nếu bạn sử dụng TCP binding (chẳng hạn như netTcpBinding), các parameters và dữ liệu return lại được format theo dạng binary.
- Tuy nhiên, khi bạn tạo những service contract có sử dụng những kiểu dữ liệu (struct/class) mà bạn build, những kiểu dữ liệu này phải được defined như là một data contract. Vậy, một data contract là một kiểu dữ liệu được đánh dấu bằng attribute [DataContract]. Mỗi field mà bạn có sử dụng của DataContract sẽ được đánh dấu bằng attribute [DataMember]. Nếu như một field nào không được đánh dấu bằng attribute [DataMember], nó sẽ không được serialized bởi WCF runtime.
- Để minh họa thêm về data contracts, ta hãy tạo một WCF service khác. Sample lần này sẽ được tạo bằng WCF service project template. Chúng ta hãy nhớ lại rằng loại WCF service này sẽ được tự động host trong IIS, và chúng sẽ hoạt động như một .NET XML web service. Khi đã nắm được tính chất của các WCF service như vậy, bạn sẽ ít gặp phải problem khi port một WCF service có sẵn vào IIS virtual directory.
Using the Web-Centric WCF Service Project Template
- Bạn hãy tạo new ASP.NET website hoặc ASP.NET webservice application, rồi xóa hết những thứ mà project template này sinh ra như các file cs, các file asmx:
Hình 6: Tạo một project web để host service trong IIS
* Trong sample gốc của sách, họ sử dụng đến code của một phần của chương khác nên tui sẽ dùng một sample khác sử dụng database NorthWind.
- Trong ví dụ này tui sẽ tạo một class library và call library này trong project web. Bạn hãy tạo một WCF Service Library project, lưu ý là đổi tên file App.config hoặc xóa nó đi để khi start project web, nó không tự động start WCF Service host luôn. Bây giờ ta tạo service contract INorthWindService.cs và code của service contract như sau:
public interface INorthWindService
{
[OperationContract]
Customer GetCustomer(string customerId);
[OperationContract]
void AddCustomer(Customer customer);
[OperationContract]
void AddCustomer(string customerId, string companyName, string contactName, string contactTitle, string address, string city, string region,
string postalCode, string country, string phone, string fax);
}
Code 4: NorthWind service contract
- Interface bên trên gồm 3 methods, một trong số đó returns một mảng các object Customer. Sau đây là code của lớp Customer:
[DataContract]
public class Customer
{
public Customer()
{ }
private string _CustomerID;
[DataMember]
public string CustomerID
{
get { return _CustomerID; }
set { _CustomerID = value; }
}
private string _CompanyName;
[DataMember]
public string CompanyName
{
get { return _CompanyName; }
set { _CompanyName = value; }
}
private string _ContactName;
[DataMember]
public string ContactName
{
get { return _ContactName; }
set { _ContactName = value; }
}
private string _ContactTitle;
[DataMember]
public string ContactTitle
{
get { return _ContactTitle; }
set { _ContactTitle = value; }
}
private string _Address;
[DataMember]
public string Address
{
get { return _Address; }
set { _Address = value; }
}
private string _City;
[DataMember]
public string City
{
get { return _City; }
set { _City = value; }
}
private string _Region;
[DataMember]
public string Region
{
get { return _Region; }
set { _Region = value; }
}
private string _PostalCode;
[DataMember]
public string PostalCode
{
get { return _PostalCode; }
set { _PostalCode = value; }
}
private string _Country;
[DataMember]
public string Country
{
get { return _Country; }
set { _Country = value; }
}
private string _Phone;
[DataMember]
public string Phone
{
get { return _Phone; }
set { _Phone = value; }
}
private string _Fax;
[DataMember]
public string Fax
{
get { return _Fax; }
set { _Fax = value; }
}
}
Code 5: Code data contract Customer
- Nếu bạn cứ implement interface như thông thường, tạo một host và call những methods này từ client, bạn sẽ bị runtime exception . Lý do là mỗi method exposed từ service phải có tên duy nhất, ở đây ta có 2 method có cùng tên là AddCustomer. Overloading không work trong web service specifications. Nhưng thật may mắn là [OperationContract] attribute support một property là Name giúp bạn đổi tên của method này trong WSDL description. Chúng ta hãy update method này như sau trong service contract:
public interface INorthWindService
{
...
[OperationContract(Name="AddCustomerDetails")]
void AddCustomer(Customer customer);
}
Code 6: Sử dụng property Name trong OperationContract
Implementing the Service Contract
- Bạn hãy download code sample ở link bên dưới của bài viết này để xem code hoàn chỉnh của solution. Database sử dụng là NorthWind, sẽ tự động attach vào SQL EXPRESS của bạn, nếu trong database server của bạn đã có sẵn database NorthWind thì hãy sửa lại connection string trong file Web.config.
The Role of the *.svc File
- Khi bạn tạo một WCF service theo style của web-service, bạn sẽ thấy trong project có một file tên là *.svc. File này được sử dụng bởi IIS để host service của bạn; nó mô tả tên và location của service implementation. Chúng ta đã đổi tên của WCF types nên phải đổi luôn contents của file Service.svc như sau:
<%@ ServiceHost Language="C#"
Service="nthoai.blogspot.com.WCFSample.ServiceLibary.NorthWindService"
Factory="System.ServiceModel.Activation.ServiceHostFactory" %>
Code 7: File service.svc
- Các bạn chú ý rằng khi host service của mình trong IIS, thì trong file service.svc bắt buộc có một attribute là Factory. Attribute này mặc định ta có thể để là System.ServiceModel.Activation.ServiceHostFactory. Người ta thường extend class ServiceHostFactory để thêm vào một số xử lý đặc biệt như logging,… Trong ví dụ này chúng ta sẽ để giá trị mặc định cho attribute Factory.
Updating the Web.config File
- Bước cuối cùng là update <system.serviceModel> trong web.config:
behaviorConfiguration="WCFSample.ServiceLibary.NorthWindServiceBehavior">
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address="" binding="wsHttpBinding" contract="nthoai.blogspot.com.WCFSample.ServiceLibary.INorthWindService">
<!--
Upon deployment, the following identity element should be removed or replaced to reflect the
identity under which the deployed service runs. If removed, WCF will infer an appropriate identity
automatically. -->
</identity>
</endpoint>
<!-- Metadata Endpoints -->
<!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. -->
<!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="True"/>
<!-- To receive exception details in faults for debugging purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="False"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Code 8: File web.config
Testing the Service
- Bây giờ chúng ta có thể build bất kì một chương trình client nào để call thử service này. Ở đây, ta sẽ thử bằng chương trình WcfTestClient như đã giới thiệu ở phần trước (Trong code sample, address của service sẽ khác so với trong bài viết):
- Hình dưới đây sẽ là kết quả khi ta gọi method GetCustomer()
Hình 7: Kết quả gọi method GetCustomer
Tổng kết:
- Loạt bài này giới thiệu sơ lược các tính năng và cách sử dụng Windows Communication Foundation (WCF) API. WCF là một trong 3 công nghệ mới của .NET 3.0. Như đã giới thiệu, động cơ chính của sự ra đời WCF là để thống nhất các công nghệ .NET distributed được giới thiệu trước đây. Một WCF service hoàn chỉnh được xác định bởi address, bindings và contracts nên sẽ rất dễ nhớ khi ta chú ý các từ đầu tiên của các thành phần này: ABC.
- Một WCF application điển hình cần 3 assemblies. Assembly đầu tiên sẽ định nghĩa service contract và service types, các thành phần này sẽ tạo thành những chức năng của service. Assembly này kế tiếp sẽ được host trong một chương trình nào đó, một IIS virtual directory hay một Windows service. Cuối cùng, một client assembly sẽ sử dụng một tool để generate các proxy code và client config để có thể thực hiện việc gọi các remote methods.
- Trong các bài viết cũng có nhắc đến một số các WCF programming tool như SvcConfigEditor.exe (giúp bạn modify các file config dễ dàng trên GUI), WcfTestClient.exe application (giúp bạn test nhanh bất kì một WCF service nào), và nhiều Visual Studio 2008 WCF project templates.
(Hết)
Code sample : Download
Xem Introduction Windows Communication Foundation Part1
Xem Introduction Windows Communication Foundation Part2
Xem Introduction Windows Communication Foundation Part3
Xem Introduction Windows Communication Foundation Part4
Introduction Windows Communication Foundation Part4
Posted On Tuesday, February 17, 2009 at at 11:04 AM by UnknownBài viết này được dịch từ Chapter 25 - INTRODUCING WINDOWS COMMUNICATION FOUNDATION của sách Pro C# 2008 and the NET 3.5 Platform Fourth Edition.
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 và MagicEightBallServiceLib project ở phần trước, rồi thêm 2 namespace System.ServiceModel và MagicEightBallServiceLib vào file programe.cs như hình:
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.
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:
- Xác định “endpoint” cho WCF service sắp được host bên trong file config.
- Bên trong code, sử dụng class “ServiceHost” để expose các service của bạn từ “endpoint” trên
- Đả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):
<configuration>
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://
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:
{
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ê)
***** 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
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:
<configuration>
<endpoint address="" binding="basicHttpBinding"
contract="MagicEightBallServiceLib.IEightBall"/>
<!-- List all of the base addresses in a dedicated section-->
<host>
</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.
- 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:
</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:
<configuration>
<!-- 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>
</host>
</service>
</services>
<!-- A behavior definition for MEX -->
<behaviors>
</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:
- 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.
Hình 2: WCF service homepage
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.
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.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
<endpoint
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
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:
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:
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
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ả.
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:
{
[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:
{
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.
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.
- 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):
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.
Hình 6: Start chương trình config editor
- 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.
Hình 7: Giao diện chương trình config editor
Code sample : Download
(Còn tiếp phần cuối)