Understanding Partial Views in ASP.NET MVC Application


Abstract:
In ASP.NET WebForms, UserControls were used to break the application into smaller pieces. Each piece represented an important part of the application. In ASP.NET MVC application you can achieve the same effect using RenderPartial and RenderAction methods. In this article we are going to demonstrate how to use RenderPartial to construct and use partial views.
Understanding RenderPartial:
RenderPartial serves the purpose of rendering a UserControl in an ASP.NET MVC application. The views rendered are called PartialViews. In order to use a partial view in your application add a MVC UserControl to your application. The screenshot below shows which project template to select when adding a user control to your MVC application.

You can add the MVC View UserControl in your current view folder or in the shared folder. First the view folder will be searched for the specified user control followed by the shared folder.
We have added a simple "Categories.ascx" to our views folder. Now, let’s see how we can load the partial views on the page. Inside the view page you can load the partial view using RenderPartial HTML helper method.

Code Snippet
  1. <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"><h2>List</h2>
  2. <% Html.RenderPartial("Categories"); %> </asp:Content>

 

Now, if you run the page you will see that the partial view is loaded inside the view page as shown in the screenshot below:

Passing Data to Partial View:
In the previous example our partial view was independent which means it was not dependent on any data populated by the view page. In real world applications this might not be the case. We may need to pass additional data to our partial view. The good news is that the partial view has access to the same ViewData dictionary which is used by the view page.
Consider a situation in which we need to pass a list of categories to the partial view. The view page List.aspx has the controller CategoryController. The controller List action is responsible for populating the categories in the ViewData as shown below:

 

Code Snippet
  1. public ActionResult List()
  2. {
  3. var categories = new List<Category>(){new Category() {Name = "Beverages"},new Category() {Name = "Condiments"},new Category() {Name = "Meat"}};ViewData["Categories"] = categories;return View();
  4. }

 

Now, the Categories.ascx partial view can easily access the ViewData["Categories"] as shown below:


 

Code Snippet
  1. <h2>Categories</h2><% foreach (var category in ((IEnumerable<Category>)ViewData["Categories"])){ %><li><%= category.Name %></li><% } %>

This shows that the ViewData dictionary is shared between the view page and the view user control (partial view). We can even make it better by strong typing the partial view and sending the model as a second parameter to the RenderPartial method. The code below shows how to make the ViewUserControl as a strongly typed view which can handle IEnumerable<Category> collection.

Code Snippet
  1. <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Category>>" %><%@ Import Namespace="MyMVCApplication.Models"%><%@ Import Namespace="Microsoft.Web.Mvc"%><h2>Categories</h2><% foreach (var category in Model){ %><li> <%= category.Name %> </li>
  2. <% } %>

 

And here is the RenderPartial method passing the Model as the second parameter.


 

Code Snippet
  1. <% Html.RenderPartial("Categories",ViewData["Categories"]); %>

Or even better you can assign the ViewData.Model and use that to pass the Model to the RenderPartial method.

Code Snippet
  1. <% Html.RenderPartial("Categories",Model); %>

The result is shown below:

Since, the ViewData dictionary is shared between the ViewUserControl and the ViewPage you can easily make changes to the object in the ViewUserControl and it will be reflected in the ViewPage using the controller.
Caching Partial Views:
In WebForms you could easily cache the contents of the UserControl. Let’s check out how we can cache partial views in an ASP.NET MVC application.
Using OutputCache Directive:
The most direct way of caching the partial views is by using the OutputCache directive. Let’s add the directive on the ViewUserControl and see the result.


 

Code– Sokhanh03 Blog
  1. <%@ OutputCache Duration="60" VaryByParam="None" %><h2>Categories</h2>Categories.ascx: <%= DateTime.Now.ToLongTimeString() %>

We are caching the ViewUserControl to "60" seconds which means it is cached to 1 minute. The DateTime is displayed on the view to indicate the request time. The DateTime value will indicate if the partial view is cached or not.  
The view page List.aspx is also adjusted. It now includes an ActionLink which will call the "List" action. It also consists of a DateTime indicator just like ViewUserControl.

Code Snippet
  1. List.aspx: <%= DateTime.Now.ToLongTimeString() %><% Html.RenderPartial("Categories",Model); %><%= Html.ActionLink<CategoryController>( x=> x.List(),"Show List") %>

When you run the page and click the "Show List" button you will find out that the view user control "Categories" is never cached. Both the view page and the view user control will show the same time. There is a problem inHtml.RenderPartial which prevents it from caching the user control. Html.RenderPartial method completely ignores the OutputCache directive in the user control. 
Using OutputCache Action Filters:
Our next technique is to use the OutputCache action filters to cache the contents of the action. This means that we need to return the user control from the controller action. This is performed by using RenderAction HTML helper method. The render action method will invoke the action on the controller and inject the returned HTML to the calling page.

Code Snippet
  1. List.aspx: <%= DateTime.Now.ToLongTimeString() %><% Html.RenderAction("PartialList"); %><%= Html.ActionLink<CategoryController>( x=> x.List(),"Show List") %>

The RenderAction in the above code will invoke the "PartialList" action which is defined below:


 

Code Snippet
  1. [OutputCache(Duration = 60, VaryByParam = "None")]public ActionResult PartialList(){var categories = new List<Category>(){new Category() {Name = "Beverages"},new Category() {Name = "Condiments"},new Category() {Name = "Meat"}};ViewData.Model = categories;return View("Categories");}

The result is shown in the screenshot below:

The screenshot above shows that the complete view page along with the partial view is cached. Once, again we have failed to cached the component. Let’s see our last approach.
WebForms Engine to the Rescue:
Phil Haack blogged about this method a while ago. He leveraged the power of the WebForms engine to cache the partial view. You can read his post here.
The idea is simple! We are going to use our view user control as a ASP.NET WebForms user control using arunat="server" tag. First, we need to register our user control in the directive which is accomplished using the following code:


 

Code Snippet
  1. <%@ Register Src ="~/Views/Category/Categories.ascx" TagName="Partial" TagPrefix="mvc" %>

Now, we can use the UserControl in our page using the code below:

 

Code Snippet
  1. <mvc:Partial runat="server" />

Now, if you run the application and click the "Show List" button you will notice that the user control is cached at a differen t time than the page.

Hopefully, in the future release of MVC the defect in RenderPartial wil be fixed!  
Conclusion:
In this article we learned about Partial Views. We also learned how to perform caching using partial views. In the next article we are going to take a look at the RenderAction HTML helper method and how it can be used in an ASP.NET MVC application.
[Download Sample]

Introduction Windows Communication Foundation Part2


Bà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.

The Role of WCF

– Như đã trình bày trong phần trước, việc có quá nhiều công nghệ distributed làm cho developer khó khăn trong việc lựa chọn. Thậm chí khi đã chọn được một công nghệ nào đó để sử dụng, việc build, maintain và config cho application cũng không mấy dễ dàng. Vì thế trước khi có .NET 3.0, rất khó để có thể “plug and play” các distributed API mà không có sự chuẩn bị cẩn thận từ trước. Ví dụ như bạn đang build hệ thống của mình bằng .NET remoting APIs, nhưng sau đó lại thấy rằng XML web services là giải pháp tốt hơn, khi đó có lẽ bạn phải chịu khó code lại.:bbpcuoi3:

– WCF là một distributed computing toolkit được giới thiệu trong .NET 3.0, nó có thể tổng hợp các công nghệ distributed trước đó. Khi sử dụng WCF, bạn có thể expose services của mình cho người khác mà không cần quan tâm xem người ta sử dụng công nghệ gì. Ví dụ như bạn đang build một “in-house” application, các máy trong hệ thống của bạn đều sử dụng hệ điều hành Windows, khi đó bạn có thể dùng nhiều TCP protocols khác nhau mà WCF hỗ trợ để được hiệu năng cao nhất. Đồng thời, service đó cũng có thể được expose ra ngoài bằng XML web service protocol để người khác có thể gọi các functions của service này mà không cần biết họ sử dụng ngôn ngữ lập trình nào cũng như chạy hệ điều hành gì.

An Overview of WCF Features

– Có thể sử dụng và phối hợp các APIs khác nhau mới chỉ là 2 chức năng nhỏ của WCF. Thêm vào đấy, WCF còn bổ trợ các kĩ thuật remoting mà nó expose. Các chứng năng đó như sau:

  • Hỗ trợ strongly typed cũng như untyped message. Hướng tiếp cận này cho phép các .NET application có thể dùng chung các custom types rất hiệu quả. Trong khi đó các software được build trên những platform khác như J2EE có thể hiểu được các loosely typed trong XML.
  • Hỗ trợ nhiều kiểu bindings khác nhau (HTTP, TCP, MSMQ, và named pipes) cho phép bạn chọn hình thức transport data hợp lý nhất.
  • Hỗ trợ các chuẩn web service specification mới nhất (WS-*)
  • Khả năng kết hợp toàn diện các mô hình bảo mật của Win32/.NET và các kĩ thuật bảo mật khác được xây dựng dựa trên những tiêu chuẩn của web services.
  • Hỗ trợ quản lý session state và cả mô hình "one-way stateless"message

– Không chỉ có những chức năng kể trên, WCF còn hỗ trợ tracing và logging, performance counters, publish và subscribe event model, hỗ trợ transaction và nhiều thứ khác.

An Overview of Service-Oriented Architecture

– Một lợi ích khác của WCF là nó hoàn toàn dựa trên một design principles nổi tiếng là Service – oriented architecture (SOA). SOA là một mô hình thông dụng trong ngành phần mềm và mô hình này có thể được hiện thực bằng nhiều cách. Đơn giản nhất, SOA là một cách để design một hệ thống distributed mà trong đó có nhiều service có thể tự hoạt động độc lập, giao tiếp với nhau bằng cách truyền đi các message dựa trên các interfaces đã được xác định trước. (“well – defined interfaces”)

– Trong công nghệ WCF, cụm từ “well – defined interfaces” được tạo ra bằng các CLR interface types. Tuy nhiên theo một nghĩa rộng hơn, interface của một service đơn giản chỉ mô tả một tập các chức năng có thể được gọi từ “external callers”

– Khi WCF được thiết kế ra, WCF team đã follow 4 tenets (tạm dịch là tiêu chí) của SOA design principles. Trong khi các tiêu chí này được tuân thủ tự động trong lúc build các WCF application, việc hiểu rõ được 4 nguyên tắc cốt yếu của SOA có thể giúp cho WCF tiến xa hơn nữa. Phần dưới đây sẽ giới thiệu 1 chút về các tiêu chí này:

Tenet 1: Boundaries Are Explicit
– Tiêu chí này lặp lại một sự thật rằng những chức năng của một WCF service được xác định thông qua các “well – defined interfaces”. Cách duy nhất để một application khác giao tiếp với một WCF service là thông qua các interfaces, và chương trình gọi client này sẽ không hề biết các service đó được xử lý như thế nào.

Tenet 1: Service Are Autonomous
– Khi nói rằng các service là những thực thể tự trị, chúng ta đang nói đến một sự thật rằng một WCF service là một chương trình có thể hoạt động độc lập với các vấn đề liên quan đến version, deployment và installation. Đế giải thích rõ hơn điều này, chúng ta hãy quay lại khía cạnh tiêu biểu của interface-based programming. Khi một interface được tạo ra, nó không nên bị thay đổi. Khi bạn muốn mở rộng một số chức năng nào đó trong WCF service của bạn, hãy tạo ra một interface khác cho các chức năng mới.

Tenet 3: Services Communicate via Contract, Not Implementation
– Tiêu chí thứ 3 này là một hệ quả của interface-based programming, trong đó những xử lý chi tiết của một WCF service không hề có một ảnh hưởng lớn đối với các externall caller. Các WCF clients giao tiếp với nhưng services duy nhất thông qua các interfaces được service expose. Hơn nữa, nếu những chức năng của service interface có sử dụng những custom types, thì các custom types này cần được khai báo chi tiết trong “data contract”để đảm bảo rằng mọi callers có thể map dữ liệu vào một data structure nào đó.

Tenet4: Service Compatibility Is Based on Policy
– Bởi vì các CLR interface cung cấp các strongly typed contracts cho tất cả WCF clients (và rất có thể được sử dụng đế generate WSDL liên quan dựa trên kiểu binding), rất quan trọng để thấy rằng một mình các interfaces/WSDL không đủ ý nghĩa để diễn tả những gì mà một service có thể làm được. Nói như vậy, SOA cho phép chúng ta định nghĩa các “policies” đế từ đó bổ xung cho các service (chẳng hạn như yêu cầu về bảo mật để có thể sử dụng được service). Khi sử dụng các policies này, chúng ta có thể tách rời giữa phần mô tả service (the exposed interfaces) ra khỏi những mô tả về cách chúng hoạt động và cách chúng được gọi.

*** Hi vọng là bài học về lịch sử công nghệ này đã giải thích vì sao WCF là một lựa chọn tốt hơn để build những distributed application sử dụng .NET 3.0 hoặc cao hơn. Bất khi nào bạn định build một “in-house” application sử dụng TCP protocol, trao đổi thông tin giữa các chương trình trong cùng một máy bằng named pipies, hoặc expose dữ liệu cho các application khác nhờ vào web service protocols, WCF luôn là API được recommended.:bbpraroi:
– Nói thế không có nghĩa là bạn không thể sử dụng các công nghệ distributed của của .NET như Webservices/ .NET remoting. Thực sự trong vài trường hợp bạn sẽ buộc phải chọn công nghệ cũ. Trong trường hợp bạn đã sử dụng các công nghệ cũ cho một vài projects, bạn sẽ thấy rằng WCF rất dễ học, WCF cũng sử dụng file xml config, .NET attributes và những tool để generate các lớp proxy.:bbpxtay:

Investigating the Core WCF Assemblies

– Toàn bộ framework WCF được đặt trong một số .NET assemblies installed trong GAC. Bảng dưới đây mô tả sơ bộ role của từng WCF assemblies mà bạn cần để build bất kì WCF application nào.:bbpraroi:

  • System.Runtime.Serializtion.dll: định nghĩa các namespace và các types được sử dụng để serializing và deserializing các objects bên trong WCF framework.
  • System.ServiceModel.dll: là core assembly chức các types sử dụng để build các kiểu WCF application.

– Hai assemblies trên định nghĩa một số namespace và types, trong số đó có các namespaces quan trọng mà chúng ta nên biết:

  • System.Runtime.Serialization: định nghĩa một số types được dùng để control việc serizlize và deserialize bên trong WCF framework
  • System.Service.Model: là namespace chính trong đó định nghĩa các loại binding và hosting cũng như các types liên quan đến security và transactional.
  • System.ServiceModel.Configuration: định nghĩa một số types cung cấp chức năng access vô file config của WCF.
  • System.ServiceModel.Discription: định nghĩa các types cung cấp một object model để các “addresses, bindings và contracts” của WCF có thể được định nghĩa trong các file config.
  • System.ServiceModel.MsmqIntegration: bao gồm các types để tương tác với MSMQ service
  • System.ServiceModel.Security: định nghĩa một số kiểu để control security trong WCF

A brief word regarding cardspace

– Ngoài 2 assemblies kể trên, WCF còn giới thiệu một assembly thứ 3 làSystem.IdentityModel.dll. Trong assembly này bạn sẽ tìm thấy một số namespace và types khác hỗ trợ WCF CardSpace API. Công nghệ này cho phé bạn sử dụng và quản lý digital identities bên trong một WCF application. Về bản chất, CardSpace API cung cấp một mô hình thống nhất đối với các vấn đề về security trong WCF applications, chẳng hạn như caller identity, user authentication/authorization services. (Document về CardSpace API có thể tìm thấy trong .NET Framework 3.5 SDK)

The Visual Studio WCF Project Templates

– Khi bạn muốn build một WCF service, bạn hoàn toàn được phép chọn kiểu project là Class Library rồi sau đó reference đến các WCF assemblies kể trên. Ngoài ra, bạn có thể tạo một WCF service bằng cách chọn kiểu project là WCF Service Library project template trong VS.NET 2008. Project template này sẽ tự động set các references đến những WCF assemblies cần thiết; tuy nhiên, nó còn tự động generate một số “started code” cho những ai chưa quen.:bbpraroi:

The Visual Studio 2008 WCF Service Library project template

Hình 1: The Visual Studio 2008 WCF Service Library project template

– Một lợi ích khác khi chọn WCF Service Library project template là nó còn giúp bạn sinh ra 1 file app.config, điều này có thể hơi lạ khi output của project này là một dll chứ không phải 1 file excutable. Tuy nhiên, file config này rất hữu dụng khi bạn muốn debug hoặc run WCF Service Library projet, VS.NET IDE sẽ tự động chạy WCF Test Client application. Chương trình client test này (WcfTestClient.exe) sẽ đọc những setting trong file app.config để host server của bạn trước khi test. Nội dung của file config này là những setting cơ bản nhất cho một WCF service. Bạn có thể copy và paste những config này vào file config của chương trình WCF hosting chính.

– Ngoài Service library template trên, category WCF project trong menu New Project của VS.NET 2008 còn có hai project WCF template kết hợp Windows Workflow Foundation vào WCF service và một template để build một RSS library.

The WCF Service Website Project Template

– Có một template khác về WCF trong VS.NET 2008 mà bạn sẽ thấy trong New Web Site dialog box như hình dưới đây:

The Visual Studio 2008 web-based WCF Service project template

Hình 2: The Visual Studio 2008 web-based WCF Service project template

– Template này rất có ích khi bạn muốn tạo một WCF service sử dụng web service protocol. Lựa chọn này sẽ tự động tạo một IIS virtual directory để host các WCF program files, tạo file web.config để expose server thông qua HTTP, và file svc. Theo cách này, web-based WCF Service project rất tiết kiệm thời gian vì IDE đã tự động setup mọi thứ cần thiết.

– Ngược lại, nếu bạn muốn build một WCF service bằng WCF Service Library template, bạn sẽ có thể host service của mình theo nhiều cách khác nhau thay vì trong IIS như trên (custom host, Windows service, …)

The Basic Composition of a WCF Application

– Tóm lại, khi bạn muốn sử dụng công nghệ WCF để build các hệ thống distributed, về cơ bản bạn phải tạo ra ít nhất 3 assemblies::bbpnghi:

  • WCF Service assembly: dll này sẽ chứa những classes và interfaces để mô tả các chức năng mà service của bạn muốn expose ra bên ngoài.
  • WCF Service host: chương trình này được dùng để host WCF service assembly
  • WCF Client: Chương trình này sẽ gọi các chức năng của WCF service trên

– Như đã nói, WCF service assembly là một .NET class library chứa một số các WCF contracts và code implementation. Assembly "Service host" lại chính xac là một .NET excutable application. Các bạn sẽ thấy rằng WCF service có thể được host trong bất kì loại application nào (Windows Forms, Windows service, WPF applications, …) Khi bạn muốn build một kiểu host application của mình, bạn phải sử dụng đến class ServiceHost cũng như một số file config liên quan. Tuy nhiên, nếu bạn đang sử dụng IIS để làm host cho WCF service, bạn không cần phải build một custom host làm gì.:bbpraroi:

– Assembly cuối cùng là một chương trình nào đó muốn gọi các service WCF và nó có thể là bất cứ dạng .NET application nào. Tương tự như chương trình host WCF service, client application cũng phải có sử dụng những file config để mô tả cách call các service trong WCF service host.

– Hình dưới mô tả (một cách high-level) mối quan hệ giữa những assemblies trên với nhau:

A high-level look at a typical WCF application

Hình 3: A high-level look at a typical WCF application

– Chúng ta cũng nên biết rằng việc sử dụng các file config là optional. Nếu muốn, chúng ta có thể hard-code chương trình host cũng như chương trình client các setting về (endpoints, binding, address, etc). Vấn đề chính khi làm như vậy là khi muốn thay đổi gì đó, bạn phải code lại, build lại và deploy lại một số assemblies. Khi sử dụng file config, hệ thống sẽ tương đối flexible. Ta chỉ cần update lại nội dung file config rồi restart lại application.:bbpskien:

Introduction Windows Communication Foundation Part1


Bà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.

 .NET 3.0 giới thiệu một API mới hỗ trợ chúng ta build các hệ thống distributed gọi là Windows Communication Foundation (WCF). Không như những distributed APIs khác mà có thể bạn từng sử dụng (như DCOM, .NET Remoting, XML web services, …), WCF cung cấp một chuẩn lập trình thống nhất, dễ mở rộng và có thể tương tác được với các công nghệ distributed cũ. Loạt bài này sẽ giới thiệu sự cần thiết của WCF và những vấn đề sẽ giải quyết được bằng WCF, bắt đầu bằng một giới thiệu sơ qua các công nghệ distributed đã có.

A Potpourri of Distributed Computing APIs

– Hệ điều hành Windows đã cung cấp một số APIs để build những hệ thống distributed. Mọi người thường nghĩ rằng “distributed systems” thì phải có ít nhất 2 máy tính, nhưng theo nghĩa rộng thì khái niệm này nói đến 2 application nào đó cần trao đổi dữ liệu với nhau, dù chúng chạy trên cùng một máy tính. Nếu hiểu theo nghĩa này, việc chọn lựa công nghệ để sử dụng sẽ liên quan đến việc trả lời câu hỏi sau đây:

Liệu hệ thống được làm ra sẽ sử dụng “in-house”, hay nó có thể được những người bên ngoài sử dụng?

– Nếu bạn muốn build một hệ thống chỉ để sử dụng nội bộ, rất có khả năng rằng bạn sẽ phải bảo đảm mỗi máy tính trong toàn bộ hệ thống phải chạy cùng một hệ điều hành như nhau, cùng sử dụng một framework (.NET, COM, J2EE, v.v), và bạn sẽ có thể phải tuân theo các chuẩn của hệ thống bảo mật hiện tại khi implement các chứng năng như authentication và authorization. Trong tình huống như vậy, bạn buộc phải chọn đúng một công nghệ distributed API phù hợp với 1 hệ điều hành nào đó, tương thích với 1 framework nào đó.

– Ngược lại, nếu bạn đang build một hệ thống cho cả “nội bộ” lẫn những người ngoài mạng sử dụng, bạn sẽ phải đối mặt với rất nhiều vấn đề. Đầu tiên, bạn không thể buộc-không thể biết người khác phải sử dụng hệ điều hành gì, không thể ép họ dùng framework nào để tương tác với hệ thống của bạn cũng như không thể biết họ sử dụng nền tảng bảo mật nào.

– Hơn nữa, nếu bạn làm việc trong một công ty lớn hoặc trong một môi trường mạng sử dụng rất nhiều hệ điều hành khác nhau cũng như nhiều công nghệ lập trình khác nhau, thì khi đó application “nội bộ” của bạn cũng sẽ gặp vấn đề như trên. Trong những tình huống như vậy, bạn cần phải chọn một công nghệ distributed flexible để bảo đảm cho hệ thống tương lai của mình có thể được sử dụng thuận tiện nhất.

– Dựa trên lời giải đáp cho câu hỏi trên, bước tiếp theo của chúng ta là phải xác định xem chính xác là API nào nên được chọn. Phần dưới đây sẽ giới thiệu sơ lược các công nghệ distributed chính đã được sử dụng bởi những Windows developer. Sau khi xong bài học lịch sử này, bạn sẽ dễ dàng thấy được tính hữu ích của Windows Communication Foundation.:bbpxtay:

The Role of DCOM

– Trước thời của .NET, Distributed Component Object Model (DCOM) là lựa chọn tối ưu trong cách distrubuted APIs. Một lợi ích của DCOM là nó cho phép tính “không phụ thuộc vị trí” đối với các components. Nghĩa là nó cho phép những phần mềm phía client được lập trình sao cho “địa chỉ vật lý” của các remote objects không bắt buộc phải hard-code. Cho dù các remote object nằm cùng một máy tính hay trên các máy khác ở một network khác thì cũng không ảnh hưởng bởi vì “địa chỉ” thật sự được lưu bên ngoài hệ thống (bên trong registry).

– DCOM đã đạt được một số thành công nhất định đối với các phần mềm Windows. DCOM cũng đã được thử port sang một số hệ điều hành khác nhưng kết quả không mấy sáng lạn, DCOM một mình nó không đưa ra một bộ khung toàn diện để build những giải pháp liên quan đến nhiều hệ điều hành (Windows, Unix, Mac) hay có thể chia sẽ data giữa nhiều nền tảng công nghệ khác nhau (COM, J2EE, CORBA, …)

– Thông thường, DCOM là một lựa chọn khá thích hợp cho các ứng dụng nội bộ bởi vì expose các COM types ra phạm vi ngoài mạng công ty của bạn có thể gặp phải một số vấn đề phức tạp như firewalls. Với sự ra đời của .NET, DCOM nhanh chóng trở nên lạc hậu. Vì vậy, trừ khi bạn phải maintain 1 hệ thống cũ có sử dụng DCOM, còn không ta có thể xem nó như là một công nghệ của quá khứ.:bbpraroi:

The Role of COM+/Enterprise Services

– DCOM chỉ định nghĩa một cách để thiết lập một kênh giao tiếp giữa hai phần mềm COM. Để bổ sung những yêu cầu khác khi build một giải pháp distrubuted computing toàn diện, Microsoft vào phút cuối đã đưa ra một công nghệ khác là Microsoft Transaction Server (MTS) rồi sau đó đổi tên thành COM+ ở một release sau đó.

– Bất chấp tên gọi, COM+ không chỉ được dùng bởi những COM developer, nó còn được sử dụng bởi những .NET developer. Từ phiên bản đầu tiên của .NET đã có chứa một namespace là System.EnterpriseServices. Nhờ nó, người dùng .NET có thể tạo ra những managed library để có thể install vào môi trường COM+, để có thể truy xuất những COM services. Trong trường hợp nào đi nữa, một “COM+ aware library” khi được install vào “COM+ runtime” sẽ được gọi là một “serviced component”

– COM+ cung cấp một số features mà các serviced component có thể sử dụng, bao gồm transaction management, objet lifetime management, pooling services, role-based security system, không phụ thuộc mô hình event, v.v. Đó chính là những lợi ích chính vào thời điểm đó vì hầu hết các hệ thống distributed system đều cần những tính năng như vậy. Một trong những cái rất thuyết phục của COM+ là khả năng điều chỉnh các setting dễ dàng bằng các administrative tools.

– Trong khi COM+/Enterprise Services vẫn còn được sử dụng, công nghệ này một lần nữa lại là “Windows-only solution” và thực sự chỉ thích hợp với các giải pháp “in-house” hoặc đóng vai trò như một back-end service cho một hệ thống khác, một public website chẳng hạn có thể call 1 serviced components (COM+ objects) ở background.

– WCF không hỗ trợ build những serviced components. Tuy nhiên nó cung cấp một phương pháp để các WCF services giao tiếp với các COM+ objects. Nếu bạn muốn build một serviced components bằng C#, bạn phải dử dụng trực tiếp namespace System.EnterpriseServices. :bbpbuon:

The Role of MSMQ

– Microsoft Message Queuing (MSMQ) API cho phép developer build những hệ thống distributed cần tính tin cậy cao khi gửi/nhận những dữ liệu trong network. Như chúng ta đều biết, trong bất kì distributed system nào cũng đều có một nguy cơ là các server có thể bị down bất cứ lúc nào, database server offline hay các kết nối mạng bị đứt giữa chừng. Hơn nữa, có một số application cần được thiết kế để có thể lưu giữ những message để rồi có thể truyền đi sau đó (queuing data).

– Lúc đầu, MSMQ được đóng gói như một thư việc cấp thấp C và các COM objects. Khi sử dụng System.Message namespace, .NET developer có thể hook vào MSMQ và build những application có thể giao tiếp với những application mà không có kết nối liên tục. Thêm nữa, COM+ layer có thể kết hợp với các chức năng của MSMQ bằng một kĩ thuật gọi là Queued Components (QC).

– Bất kể bạn dùng kĩ thuật nào để tương tác với MSMQ runtime, cuối cùng bạn cần đảm bảo rằng application mình viết có thể gửi đi những Message đúng nơi đúng lúc. Cũng giống như COM+, MSMQ vẫn còn được sử dụng để build những distributed software trong môi trường Windows.:bbpbuon:

The Role of .NET Remoting

– Như đã nói ở trên, cùng với sự ra đời của .NET platform, DCOM mau chóng trở nên lỗi thời. Và thay vào đó là một .NET class libraries được đóng gói sẵn trong .NET remoting layer: System.Runtime.Remoting. API này cho phép nhiều máy tính có thể host nhiều remoted objects, tất nhiên chúng phải chạy những ứng dụng .NET.

– .NET remoting API có một số những tính năng rất hữu dụng. Trong đó, tính năng quan trọng nhất chính là khả năng sử dụng file xml config để có thể khai báo những seting quan trọng cho phép client và server có thể giao tiếp với nhau theo nhiều cách. Bằng cách này, sẽ rất dễ dàng để thay đổi tính năng của application chỉ với một vài chỉnh sửa file config và restart application.

– Thực sự rằng API này chỉ có thể sử dụng bởi những application .NET, nhờ đó bạn có thể thừa hưởng được nhiều lợi ích, như là data có thể được mã hóa và nén ở dạng binary, có thể sử dụng ngay các Common Type System (CTS) khi khai báo biến và return values. Thực ra với công nghệ này có thể sử dụng .Net để build những distributed system mà có thể chạy trên nhiều hệ điều hành khác nhau (sử dụng MONO), tương tác với các nền tảng khác như J2EE …:bbpskien:

The Role of XML Web Services

– Các distributed APIs ra đời trước đều hỗ trợ rất ít (nếu có) khả năng access đến các chức năng của hệ thống từ một caller chưa biết. Khi bạn cần đưa ra một số services để người khác có thể sử dụng không cần biết người đó sử dụng hệ điều hành gì và công nghệ nào thì XML web services có vẽ như là lựa chọn hợp lý nhất.

– Không như các web application thông dụng, một web service được sử dụng để expose các chứng năng của remote components nhờ vào web protocols. Trong phiên bản đầu của .NET, developer được cung cấp một số chức năng để build và gọi (consuming) XML web services trong namespaceSystem.Web.Services. Thực ra bây giờ người ta chỉ việc sử dụng attribute [WebMethod] cho mỗi public method mà bạn muốn người khác có thể sử dụng. Hơn nữa, Visual Studio 2008 còn cho phép bạn connect đến một remote web service chỉ với vài cái click.:bbpraroi:

– Web services cho phép developer build những .NET assemblies với những .NET types có thể được gọi thông qua giao thức HTTP đơn giản. Hơn nữa, một web service có thể mã hóa dữ liệu của nó theo chuẩn XML. Công nghệ Web service dựa trên các tiêu chuẩn của ngành phần mềm như HTTP, XML, SOAP thay vì một số kĩ thuật đặc thù như DCOM hay .NET remoting, chúng nâng cao khả năng giao tiếp tối đa giữa các hệ thống khác nhau.

– Tất nhiên không có một distributed API nào là hoàn hảo. Một trở ngại tiềm tàng của web services là vấn đề về performance (sử dụng HTTP và XML), và nó có thể không phải là một lựa chọn tốt để build những ứng dụng “in-house” khi mà TCP-based protocol và dữ liệu ở dạng binary format có thể được sử dụng mà không gặp bất cứ trở ngại nào.:bbpxtay:

XML web services allow for a very high degree of interoperability

Hình 1: XML web services allow for a very high degree of interoperability

Web Service Standars

– Một vấn đề dễ thấy nhất là có khá nhiều ông lớn như Microsoft, IBM và Sun Microsystems tạo ra các chuẩn Web Services của riêng mình và các chuẩn này không 100% tương thích với nhau. Hiển nhiên đó là một vấn đề rất đau đầu, chúng ta đều biết rằng mục đích của Web service là tạo ra khả năng tương tác cao giữa các hệ thống không phụ thuộc platforms và hệ điều hành.:bbptuc:

– Để bảo đảm tính độc lập môi trường của Web Service, những tổ chức như World Wide Web Consortium (W3C; http://www.w3.org) và Web Services Interoperatibility Organization (WS-I: http://www.ws-i.org) đã đứng ra xem xét các đặc tả để vạch ra những điều chi tiết để các software vendor (như IBM, Microsoft, Sun,..) nên build những công nghệ của họ như thế nào để bảo đảm tính tương thích với nhau.

– Tập hợp các đặc tả này được đặt tên theo kiểu prefix WS-, bao gồm các vấn đề về security, attachments, description của web services (Web Service Description Language, hay WSDL), policies, SOAP formats, và một số những vấn đề quan trọng khác.

– Có thể bạn đã biết rằng Microsoft đã hỗ trợ hầu hết các chuẩn trên trong Web Services Enhancements (WSE) 3.0 toolkit, bạn có thể download nó ở website: http://msdn2.microsoft.com/en-us/webservices

– Khi bạn build những WCF service applications, bạn sẽ không cần sử dụng trực tiếp các assemblies của WSE 3.0 toolkit. Ngoài ra, nếu bạn build những WCF service sử dụng HTTP-based binding, mặc định các đặc tả WS-* sẽ có sẵn cho bạn.

Named Pipes, Sockets, and P2P

– Nếu như DCOM, .NET Remoting, web services, COM+ và MSMQ vẫn chưa đủ “challenge” đối với bạn :bbpcuoi3:thì bạn có thể sử dụng các APIs giao tiếp khác như pipes, sockets và peer-to-peer (P2P) services. Những APIs cấp thấp này hứa hẹn sẽ có performance cao hơn nhiều đặc biệt đối với những máy LAN nhưng bù lại sử dụng chúng sẽ khá phức tạp.

– Nếu bạn phải build những hệ thống distributed mà các application chạy trên cùng một máy, bạn có thể sử dụng “named pipes” API trong namespace System.IO.Pipes (.NET 3.5). Kĩ thuật này là cách nhanh nhất để truyền data giữa các applications trong cùng một máy tính.

– Cuối cùng, nếu bạn build những applications cần đi sâu chi tiết cách truyền dữ liệu trên network thì sockets và P2P có thể được dùng trong các namespace System.Net.Sockets  System.Net.PeerToPeer.

Roland Weigelt’s G h o s t D o c


Code 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:

Using 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/

Pro Spring 2.5


Product Details

  • Paperback: 920 pages
  • Publisher: Apress (August 15, 2008)
  • Language: English
  • ISBN-10: 1590599217
  • ISBN-13: 978-1590599211

Product Description

The Spring Framework 2.5 release reflects the state of the art in both the Spring Framework and enterprise Java frameworks as a whole. A guidebook to this critical tool is necessary reading for any conscientious Java developer.

— Rob Harrop, author of Pro Spring

The move from so–called heavyweight architectures, such as Enterprise JavaBeans, toward lightweight frameworks, like Spring, has not stopped since Pro Spring was published by Rob Harrop and Jan Machacek in 2005; in fact, it’s picked up pace. The Spring Framework remains the leader in this move and provides a platform on which you can build your own applications and services.

Pro Spring 2.5 covers the new features of Spring 2.5, but moreover, it is focused on the best practices and core standards of contemporary Spring development. As members of the Spring development team at Cake Solutions, the author team brings extensive practical experience gained from working with Spring since version 1.0 and delivering successful systems on top of it.

Learn the approaches that really matter in a professional, enterprise–level environment, so you can apply them to your projects today, safe in the knowledge that they just work.

What You’ll Learn
  • Discover how to use Spring’s Inversion of Control (IoC).
  • Explore Spring’s excellent aspect–oriented programming (AOP) support, including Spring 2.5’s new @AspectJ feature.
  • Find out how to use Spring’s dynamic scripting language features, Spring design patterns, and performance tuning in Spring applications.
  • Learn what really works in real–world Spring development.
  • Understand Spring’s support for the JDBC framework, Hibernate, the Quartz enterprise scheduler, declarative transaction management, and much more.
  • Master Spring’s well–designed MVC framework and add AJAX to your Spring web applications to create flexible, efficient, and manageable applications using the best techniques available.
Who is this book for?

Enterprise Java, J2EE/Java EE developers looking to learn and use the Spring metaframework, the now growing, leading alternative to J2EE/Java EE

About the Apress Pro Series

The Apress Pro series books are practical, professional tutorials to keep you on and moving up the professional ladder.

You have gotten the job, now you need to hone your skills in these tough competitive times. The Apress Pro series expands your skills and expertise in exactly the areas you need. Master the content of a Pro book, and you will always be able to get the job done in a professional development project. Written by experts in their field, Pro series books from Apress give you the hard-won solutions to problems you will face in your professional programming career.

About the Author

Jan Machacek is a chief software architect at Cake Solutions Limited (www.cakesolutions.net), a UK-based software company. He has been an early adopter of Spring at Cake Solutions and has seen the dramatic change the Spring framework has brought to the Java world. As part of his job, Jan designs and oversees the development of majority of Cake’s projects. Where appropriate, Jan also applies his interest in declarative programming and artificial intelligence. Throughout his programming career, Jan has designed and implemented large J2EE and .NET systems for the UK government and large private sector bodies. When not programming, Jan enjoys foreign languages; he also enters races and time trials as a member of the Manchester Wheelers’ cycling club.

Jessica Ditt is a developer at Cake Solutions Limited. She joined the Cake team in 2005 and has worked on numerous enterprise-level projects, all of which were written using the Spring framework. Jessica has been an early adopter of Spring Webflow at Cake and has become an expert in efficient indexing using Lucene and monitoring deployed systems using JMX. Out of the office, Jessica is a keen volleyball player.

Aleksa Vukotic is senior developer of Cake Solutions Limited. He joined Cake Solutions in June 2004. Since joining Cake, Aleksa has worked on numerous Java projects using the Spring framework for variety of clients. His work includes sophisticated systems for the UK government agencies. As part of his role at Cake, Aleksa helps other members of the team with some of the most complex problems, especially related to data access and MVC. He graduated in computer science and engineering at the School of Electrical Engineering, Belgrade University, Serbia.
In his spare time, Aleksa enjoys nights out and computer games.

Anirvan Cakraborty is a developer at Cake Solutions Limited. Since becoming a member of the Cake team in 2006, Anirvan has worked on the more complex projects, including the UK government knowledge management system. Anirvan is a contributor to Lucene integration in the Spring Modules project. Prior to joining Cake, Anirvan completed his master’s degree in Internet software systems at the School of Computer Science, University of Birmingham, United Kingdom. When not programming, Anirvan enjoys following sports like Cricket and Formula One. He also enjoys reading detective novels and watching movies.

For more free books download visit this blog daily

For the Broken Links and Like this Book reply Here….


Download
OR
Download
OR
Download
OR
Download
OR
Download

Eclipse 2 for Java Developers


Eclipse 2 for Java Developers

https://i0.wp.com/images.shopping.msn.com/img/2/2949/53/792045.gif

Product Details

  • Paperback: 478 pages
  • Publisher: Wiley; 1 edition (December 19, 2003)
  • Language: English
  • ISBN-10: 0470869054
  • ISBN-13: 978-0470869055

Product Description
Eclipse – the open source and most popular Java IDE – integrates best-of-breed tools such as JUnit and Ant. As a community version of IBM’s Websphere Studio Application Developer (WDAD), Eclipse offers developers a wonderful opportunity to work in and get acquainted with this technology.  It increases productivity and makes code building, testing, debugging, and deploying easier and more streamlined. The plug-in architecture of Eclipse has spawned a large number of Eclipse related sub-projects. With already hundreds of thousands of users worldwide, Eclipse will be the development platform of choice for a large proportion of the Java community.

The book is organised in 3 Parts.  In the first part, readers are introduced to the Eclipse Java IDE and shown how projects are laid out and the various facilities to help write Java code. To illustrate this a lip synchronization for the Java FreeTTS speech synthesis package is implemented. In Part 2, SWT and JFace (Eclipse’s alternative to the Java AWT and Swing) are described and demonstrated in practice in a JavaLayer based MP3 player. In Part 3 the author shows how Eclipse can be used as a tool platform and an application framework. An Aspell based spell checker that seamlessly integrates into the Eclipse platform and can be used in all text based Eclipse editors is given as an example of how powerful it can be to work within this environment.

Designed for Java developers getting up to speed with Eclipse, there is excellent coverage of JFace and SWT;  details on how to reuse and extend existing Eclipse components; a guide on how to import third party code and integrate it with your own code, and  real-world examples with the code provided on the accompanying website.

For more free books download visit this blog daily

For the Broken Links and Like this Book reply Here….


Download
OR
Download
OR
Download
OR
Download
OR
Download
OR
Download
OR
Download
OR
Download
OR
Download

Your first NHibernate based application


Wiki extracted from the original blog post of Gabriel Schenker
Welcome to NHibernate

If you’re reading this, we assume that you’ve just downloaded NHibernate and want to get started using it.

This tutorial will talk you through the following:

  • Installing NHibernate
  • Defining a simple business object class.
  • Create an NHibernate mapping to load and save the business object.
  • Configure NHibernate to talk to your local database.
  • Automatically generate a database 
  • Writing simple CRUD code using the Repository pattern.
  • Using Unit Tests to make sure the code is working correctly.

This is what we’re aiming for:

But first things first [:)]

Lets start by actually doing something with that ZIP file you just downloaded.

Installing NHibernate

If you’ve downloaded the NHibernate binaries in a zip file, all you need to do is extract that file to somewhere sensible. I usually create a folder called SharedLibs  c:\Code\SharedLibs\NHibernate and extract the zip to there. But whatever you’re comfortable with. This is your SharedLib folder from which you need to add your references to the NHibernate and NUnit dlls. Add references to NHibernate to both the demo project and the unit test project.

That’s it! NHibernate is installed (easy huh). We’ll talk you through using it with Visual Studio in a moment. First let’s look at how we go about creating a project. Note this code is dependent on Visual Studio 2008 and .Net Framework 3.5.

Create Your Project

Before we start building our application and business objects, we’ll need to create a blank project to put them in. Fire up Visual Studio and create a new Class Library project. Let’s now look at something interesting: creating a business object.

Defining the Business Objects

Lets start by defining a very simple domain. For the moment it consists of one entity called Product. The product has 3 properties Name, Category and Discontinued.

Add a folder Domain to the FirstSample project of your solution. Add a new class Product.cs to this folder. The code is very simple and uses automatic properties (a feature of the new C# 3.0 compiler)

namespace FirstSolution.Domain
{
public class Product
{
public string Name { get; set; }
public string Category { get; set; }
public bool Discontinued { get; set; }
}
}

Now we want to be able to persist instances of this entity in a (relational) database. We have chosen NHibernatefor this task. An instance of an entity in the domain corresponds to a row in a table in the database. So we have to define a mapping between the entity and the corresponding table in the database. This mapping can be done either by defining a mapping file (an xml-document) or by decorating the entity with attributes. I’ll start with the mapping file.

Define the Mapping

Create a folder Mappings in the FirstSample project. Add a new xml-document to this folder and call itProduct.hbm.xml. Please note the "hbm" part of the file name. This is a convention used by NHibernate to automatically recognize the file as a mapping file. Define "Embedded Resource" as Build Action for this xml file.

In the Windows Explorer locate the nhibernate-mapping.xsd in the src folder of NHibernate and copy it to your SharedLibs folder. We can now use this xml schema definition file when defining our mapping files. VS will then provide intellisense and validation when editing an xml mapping document.

Back in VS add the schema to the Product.hbm.xml file

Let’s start now. Each mapping file has to define a <hibernate-mapping> root node

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="FirstSolution"
namespace="FirstSolution.Domain">

<!-- more mapping info here -->

</hibernate-mapping>

In a mapping file when referencing a domain class you always have to provide the fully qualified name of the class (e.g. FirstSample.Domain.Product, FirstSample). To make the xml less verbose you can define the assembly name (in which the domain classes are implemented and the namespace of the domain classes in the two attributes assembly andnamespace of the root node. It’s similar to the using statement in C#.

Now we have to first define a primary key for the product entity. Technically we could take the property Name of the product since this property must be defined and has to be unique. But it is common to use a surrogate key instead. For thus we add a property to our entity and call it Id. We use Guid as the type of the Id but it can as well be an int or a long.

using System;

namespace FirstSolution.Domain
{
public class Product
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Category { get; set; }
public bool Discontinued { get; set; }
}
}

The complete mapping file

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="FirstSolution"
namespace="FirstSolution.Domain">

<class name="Product">
<id name="Id">
<generator class="guid" />
</id>
<property name="Name" />
<property name="Category" />
<property name="Discontinued" />
</class>

</hibernate-mapping>

NHibernate doesn’t get in our way such as that it defines many reasonable defaults. So if you don’t provide a column name for a property explicitly it will name the column according to the property. Or NHibernate can automatically infer the name of the table or the type of the column from the class definition. As a consequence my xml mapping file is not cluttered with redundant information. Please refer to the online documentation for more detailed explanation of the mapping. You can find it here.

Your solution explorer should look like this now (Domain.cd contains the class diagram of our simple domain). You will have added the design folder and created the class diagram yourself although this is for good practice and not required for the purposes of this excercise.

Configure NHibernate

We now have to tell NHibernate which database product we want to use and provide it the connection details in form of a connection string. NHibernate supports many many database products!

Add a new xml file to the FirstSolution project and call it hibernate.cfg.xml. Set its property "Copy to Output" to "Copy always". Since we are using SQL Server Compact Edition in this first sample enter the following information into the xml file

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="dialect">NHibernate.Dialect.MsSqlCeDialect</property>
<property name="connection.driver_class">NHibernate.Driver.SqlServerCeDriver</property>
<property name="connection.connection_string">Data Source=FirstSample.sdf</property>

<property name="show_sql">true</property>
</session-factory>
</hibernate-configuration>

With this configuration file we tell NHibernate that we want to use MS SQL Server Compact Edition as our target database and that the name of the database shall be FirstSample.sdf (=connection string). We have also defined that we want to see the SQL NHibernate generates and sends to the database (highly recommended for debugging purposes during development). Double check that you have no typos in the code!

Add an empty database called FirstSample.sdf to the FirstSample project (choose Local Database as template)

Click Add and ignore the DataSet creation wizard (just hit Cancel).

Test the Setup

It’s now time to test our setup. First verify that you have the following files in your SharedLibs folder

The last 8 files you can find in the "Microsoft SQL Server Compact Edition" directory in your Programs folder.

Note: the System.Data.SqlServerCe.dll is located in the sub-folder Desktop.

All other files can be found in the NHibernate folder

Add a reference to the FirstSample project in your test project. Additionally add references to NHibernate.dll, nunit.framework.dll and Systm.Data.SqlServerCe.dll (remember to reference the files located in the SharedLibs folder!). Pay attention to set the property "Copy Local" to true for the assembly System.Data.SqlServerCe.dll since by default it is set to false! Add a copy of hibernate.cfg.xml to the root of this unit test project. Direct action with NHibernate in the NUnit project needs access to this file.

Add a class called GenerateSchema_Fixture to your test project. Your test project should now look like this

We further need the 7 files sqce*.dll in the output directory. We can do this by using a post-build event in VS. Enter the following command in the "Post-build event command line"

copy $(ProjectDir)..\..\SharedLibs\sqlce*.dll $(ProjectDir)$(OutDir)

Now add the following code to the GenerateSchema_Fixture file

using FirstSolution.Domain;
using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;
using NUnit.Framework;
 
namespace FirstSolution.Tests
{
    [TestFixture]
    public class GenerateSchema_Fixture
    {
        [Test]
        public void Can_generate_schema()
        {
            var cfg = new Configuration();
            cfg.Configure();
            cfg.AddAssembly(typeof (Product).Assembly);
            
            new SchemaExport(cfg).Execute(false, true, false, false);
        }
    }
}

The first line of the test method creates a new instance of the NHibernate configuration class. This class is used to configure NHibernate. In the second line we tell NHibernate to configure itself. NHibernate will look out for configuration information since we do not provide any information here in the test method. So NHibernate will search for a file calledhibernate.cfg.xml in the output directory. That’s exactly what we want since we have defined our settings in this file.

In the third line of the code we tell NHibernate that it can find mapping information in the assembly which contains also the class Product. At the time being it will only find one such file (Product.hbm.xml) as an embedded resource.

The fourth line of code uses the SchemaExport helper class of NHibernate to auto-"magically" generate the schema in the database for us. SchemaExport will create the product table in the database and each time you call it it will delete the table and the table data and recreate it.

Note: with this test method we do NOT want to find out whether NHibernate does its job correctly (you can be sure it does) but rater whether we have setup our system correctly. However, you can check the database and see the newly created ‘product’ table.

If you have TestDriven.Net installed you can now just right click inside the test method and choose "Run Test(s)" to execute the test.

If every thing is ok you should see the following result in the output window

If you have ReSharper installed you can just start the test by clicking the yellow-green circle on the left border and choose Run.

The result is as follows

In case of Problems

If your test fails double check that you find the following files in your target directory (that is: m:dev\projects\FirstSolution\src\FirstSolution.Tests\bin\debug)

Double check also if you have no typos in the NHibernate configuration file (hibernate.cfg.xml) or in the mapping file (Product.hbm.xml). Finally check whether you have set the "Build Action" of the mapping file (Product.hbm.xml) to "Embedded Resource". Only continue if the test succeeds.

Our first CRUD operations

Now obviously our system is ready to start. We have successfully implemented our Domain, defined the mapping files and configured NHibernate. Finally we have used NHibernate to automatically generate the database schema from our Domain (and our mapping files).

In the spirit of DDD (see e.g. Domain Driven Design by Eric Evans) we define a repository for all crud operations (create, read, update and delete). The repository interface is part of the domain where as the implementation is not! The implementation is infrastructure specific. We want to keep our domain persistence ignorant (PI).

Add a new interface to the domain folder of our FirstSolution project. Call it IProductRepository. Let’s define the following interface

using System;
using System.Collections.Generic;
 
namespace FirstSolution.Domain
{
    public interface IProductRepository
    {
        void Add(Product product);
        void Update(Product product);
        void Remove(Product product);
        Product GetById(Guid productId);
        Product GetByName(string name);
        ICollection<Product> GetByCategory(string category);
    }
}

Add a class ProductRepository_Fixture to the test project of the solution and add the following code

[TestFixture]
    public class ProductRepository_Fixture
    {
        private ISessionFactory _sessionFactory;
        private Configuration _configuration;
 
        [TestFixtureSetUp]
        public void TestFixtureSetUp()
        {
            _configuration = new Configuration();
            _configuration.Configure();
            _configuration.AddAssembly(typeof (Product).Assembly);
            _sessionFactory = _configuration.BuildSessionFactory();
        }
    }

In the fourth line of the method TestFixtureSetUp we create a session factory. This is an expensive process and should thus be executed only once. That’s the reason why I put it into this method which is only executed once during a test cycle.

To keep our test methods side effect free we re-create our database schema before the execution of each test method. Thus we add the following method

[SetUp]
public void SetupContext()
{
new SchemaExport(_configuration).Execute(false, true, false, false);
}

And now we can implement the test method to add a new product instance to the database. Start by adding a new folder called Repositories to your FirstSolution project. Add a class ProductRepository to this folder. Make theProductRepository inherit from the interface IProductRepository.

using System;
using System.Collections.Generic;
using FirstSolution.Domain;
 
namespace FirstSolution.Repositories
{
    public class ProductRepository : IProductRepository
    {
        public void Add(Product product)
        {
            throw new NotImplementedException();
        }
 
        public void Update(Product product)
        {
            throw new NotImplementedException();
        }
 
        public void Remove(Product product)
        {
            throw new NotImplementedException();
        }
 
        public Product GetById(Guid productId)
        {
            throw new NotImplementedException();
        }
 
        public Product GetByName(string name)
        {
            throw new NotImplementedException();
        }
 
        public ICollection<Product> GetByCategory(string category)
        {
            throw new NotImplementedException();
        }
    }
}
Manipulating Data

Now go back to the ProductRepository_Fixture test class and implement the first test method

      [Test]
public void Can_add_new_product()
{
var product = new Product {Name = "Apple", Category = "Fruits"};
IProductRepository repository = new ProductRepository();
repository.Add(product);
}

The first run of the test method will fail since we have not yet implemented the Add method in the repository class. Let’s do it. But wait, we have to define a little helper class first which provides us session objects on demand.

using FirstSolution.Domain;
using NHibernate;
using NHibernate.Cfg;
 
namespace FirstSolution.Repositories
{
    public class NHibernateHelper
    {
        private static ISessionFactory _sessionFactory;
 
        private static ISessionFactory SessionFactory
        {
            get
            {
                if(_sessionFactory == null)
                {
                    var configuration = new Configuration();
                    configuration.Configure();
                    configuration.AddAssembly(typeof(Product).Assembly);
                    _sessionFactory = configuration.BuildSessionFactory();
                }
                return _sessionFactory;
            }
        }
 
        public static ISession OpenSession()
        {
            return SessionFactory.OpenSession();
        }
    }
}

This class creates a session factory only the first time a client needs a new session.

Now we can define the Add method in the ProductRepository as follows

 public void Add(Product product)
{
using (ISession session = NHibernateHelper.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
session.Save(product);
transaction.Commit();
}
}

The second run of the test method will again fail with the following message

That’s because NHibernate is by default configured to use lazy load for all entities. That is the recommended approach and I warmly recommend not to change it for a maximum of flexibility.

How can we solve this issue? It’s easy we have to just make all our properties (and methods) of the domain object(s) virtual. Let’s do this for our Product class

    public class Product
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual string Category { get; set; }
public virtual bool Discontinued { get; set; }
}

Now run the test again. It should succeed and we get the following output

Note the sql spit out by NHibernate.

Now we think that we have successfully inserted a new product into the database. But let’s test it whether it is really so. Let’s extend our test method

        [Test]
        public void Can_add_new_product()
        {
            var product = new Product {Name = "Apple", Category = "Fruits"};
            IProductRepository repository = new ProductRepository();
            repository.Add(product);
 
            // use session to try to load the product
            using(ISession session = _sessionFactory.OpenSession())
            {
                var fromDb = session.Get<Product>(product.Id);
                // Test that the product was successfully inserted
                Assert.IsNotNull(fromDb);
                Assert.AreNotSame(product, fromDb);
                Assert.AreEqual(product.Name, fromDb.Name);
                Assert.AreEqual(product.Category, fromDb.Category);
            }
        }

Run the test again. Hopefully it will succeed…

Now we are ready to implement also the other methods of the repository. For testing this we would rather have a repository (that is database table) already containing some products. Nothing easier than this. Just add a method CreateInitialData to the test class as follows

private readonly Product[] _products = new[]
                 {
                     new Product {Name = "Melon", Category = "Fruits"},
                     new Product {Name = "Pear", Category = "Fruits"},
                     new Product {Name = "Milk", Category = "Beverages"},
                     new Product {Name = "Coca Cola", Category = "Beverages"},
                     new Product {Name = "Pepsi Cola", Category = "Beverages"},
                 };
 
        private void CreateInitialData()
        {
            
            using(ISession session = _sessionFactory.OpenSession())
                using(ITransaction transaction = session.BeginTransaction())
                {
                    foreach (var product in _products)
                        session.Save(product);
                    transaction.Commit();
                }
        }

Call this method from the SetupContext method (after the create schema call) and we are done. Now each time after the database schema is created the database is populated with some products.

Let’s test the Update method of the repository with the following code

        [Test]
        public void Can_update_existing_product()
        {
            var product = _products[0];
            product.Name = "Yellow Pear";
            IProductRepository repository = new ProductRepository();
            repository.Update(product);
 
            // use session to try to load the product
            using (ISession session = _sessionFactory.OpenSession())
            {
                var fromDb = session.Get<Product>(product.Id);
                Assert.AreEqual(product.Name, fromDb.Name);
            }
        }

When running for the first time this code will fail since the Update method has not yet been implemented in the repository.Note: This is the expected behavior since in TDD the first time you run a test it should always fail!

Analogous to the Add method we implement the Update method of the repository. The only difference is that we call the update method of the NHibernate session object instead of the save method.

        public void Update(Product product)
{
using (ISession session = NHibernateHelper.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
session.Update(product);
transaction.Commit();
}
}

Run the test again an watch it succeed.

The delete method is straight forward. When testing whether the record has really been deleted we just assert that the value returned by the session’s get method is equal to null. Here is the test method

       [Test]
public void Can_remove_existing_product()
{
var product = _products[0];
IProductRepository repository = new ProductRepository();
repository.Remove(product);

using (ISession session = _sessionFactory.OpenSession())
{
var fromDb = session.Get<Product>(product.Id);
Assert.IsNull(fromDb);
}
}

and here the implementation of the Remove method in the repository

        public void Remove(Product product)
{
using (ISession session = NHibernateHelper.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
session.Delete(product);
transaction.Commit();
}
}
Querying the Database

We still have to implement the three methods which query the database for objects. Let’s start with the most easy one, the GetById. First we write the test

        [Test]
public void Can_get_existing_product_by_id()
{
IProductRepository repository = new ProductRepository();
var fromDb = repository.GetById(_products[1].Id);
Assert.IsNotNull(fromDb);
Assert.AreNotSame(_products[1], fromDb);
Assert.AreEqual(_products[1].Name, fromDb.Name);
}

and then the code to fulfill the test

        public Product GetById(Guid productId)
{
using (ISession session = NHibernateHelper.OpenSession())
return session.Get<Product>(productId);
}

Now that was easy. For the following two methods we use a new method of the session object. Let’s start with the GetByName method. As usual we write the test first

       [Test]
public void Can_get_existing_product_by_name()
{
IProductRepository repository = new ProductRepository();
var fromDb = repository.GetByName(_products[1].Name);

Assert.IsNotNull(fromDb);
Assert.AreNotSame(_products[1], fromDb);
Assert.AreEqual(_products[1].Id, fromDb.Id);
}

The implementation of the GetByName method can be done by using two different approaches. The first is using HQL (Hibernate Query Language) and the second one HCQ (Hibernate Criteria Query). Let’s start with HQL. HQL is a object oriented query language similar (but not equal to) SQL.

To be added: implemetation of GetByName using HQL. Implement HCQ as below this works as expected and returns a product entity.

In the above sample I have introduced a commonly used technique when using NHibernate. It’s called fluent interfaces. As a result the code is less verbose and easier to understand. You can see that a HQL query is a string which can have embedded (named) parameters. Parameters are prefixed by a ‘:’. NHibernate defines many helper methods (like SetString used in the example) to assign values of various types to those parameters. Finally by using UniqueResult I tell NHibernate that I expect only one record to return. If more than one record is returned by the HQL query then an exception is raised. To get more information about HQL please read the online documentation.

The second version uses a criteria query to search the requested product. You need to add a reference to  NHibernate.Criterion on your repository page.

        public Product GetByName(string name)
{
using (ISession session = NHibernateHelper.OpenSession())
{
Product product = session
.CreateCriteria(typeof(Product))
.Add(Restrictions.Eq("Name", name))
.UniqueResult<Product>();
return product;
}
}

Many users of NHibernate think that this approach is more object oriented. On the other hand a complex query written with criteria syntax can quickly become difficult to understand.

The last method to implement is GetByCategory. This method returns a list of products. The test can be implemented as follows

        [Test]
public void Can_get_existing_products_by_category()
{
IProductRepository repository = new ProductRepository();
var fromDb = repository.GetByCategory("Fruits");

Assert.AreEqual(2, fromDb.Count);
Assert.IsTrue(IsInCollection(_products[0], fromDb));
Assert.IsTrue(IsInCollection(_products[1], fromDb));
}

private bool IsInCollection(Product product, ICollection<Product> fromDb)
{
foreach (var item in fromDb)
if (product.Id == item.Id)
return true;
return false;
}

and the method itself might contain the following code

        public ICollection<Product> GetByCategory(string category)
{
using (ISession session = NHibernateHelper.OpenSession())
{
var products = session
.CreateCriteria(typeof(Product))
.Add(Restrictions.Eq("Category", category))
.List<Product>();
return products;
}
}
Summary

In this article I have shown you how to implement a basic sample domain, define the mapping to a database and how to configure NHibernate to be able to persist domain objects in the database. I have shown you how to typically write and test CRUD methods for your domain objects. I have taken MS SQL Compact Edition as sample database but any other supported database can be used (you only have to change the hibernate.cfg.xml file accordingly). Ee have no dependencies on external frameworks or tools other than the database and NHibernate itself (.NET of course never counts here).