.NET Framework bao gồm 2 phần chính là Common Language Runtime (CLR) và Base Class Libraries (BCL), nhưng trên thực tế thì BCL bao gồm ASP.NET và Windows Forms, nên một số tài liệu đã giới thiệu .NET Framework bao gồm ba phần là bộ thực thi ngôn ngữ chung (Common Language Runtime), các lớp lập trình hợp nhất hay còn gọi là các thư viện lớp cơ sở (Base Class Libraries) và một phiên bản cấu thành của Microsoft Active Server Pages gọi là Microsoftđ ASP.NET Một trong các thành phần này đều có vai trò cực kỳ quan trọng trong việc phát triển các dịch vụ và các ứng dụng .NET
Common Language Runtime (gọi tắt là bộ thực thi) được xây dựng trên các dịch vụ hệ điều hành. Nó chịu trách nhiệm thực hiện các ứng dụng và đảm bảo các phần liên quan đến ứng dụng đều được đáp ứng như quản lí bộ nhớ, an ninh bảo mật, tích hợp ngôn ngữ..v.v. Bộ thực thi bao gồm nhiều dịch vụ hỗ trợ phát triển và triển khai ứng dụng cũng như cải thiện tính đáng tin cậy của ứng dụng. Tuy vậy, những nhà phát triển trên thực tế không tương tác với CLR. Họ sử dụng một tập các thư viện lớp cơ sở được xây dựng bên trên bộ thực thi này thông qua các ngôn ngữ lập trình. Như là một phần của các lớp cơ sở, .NET Framework còn cung cấp một mô hình lập trình ứng dụng Web ASP.NET và Windows Forms (để xây dựng các ứng dụng trên Windows). Riêng ASP.NET cung cấp các thành phần và các dịch vụ ở mức cao hơn nhằm mục đích phát triển các dịch vụ và các ứng dụng Web XML.
Common Language Runtime
Như các bạn đã biết, các ngôn ngữ lập trình khác nhau đều cung cấp một runtime (bộ thực thi) và .NET Framework không phải là một ngoại lệ. Tuy vậy bạn sẽ thấy bộ runtime này là khá đặc biệt so với phần lớn các runtime chúng ta vẫn sử dụng.
Common Language Runtime trong .NET Framework quản lý sự thực hiện mã và cung cấp sự truy cập vào nhiều loại dịch vụ giúp cho quá trình phát triển được dễ dàng hơn. CLR đã được phát triển ở tầm cao hơn so với các runtime trước đây như VB-runtime chẳng hạn, bởi nó đạt được những khả nǎng như tích hợp các ngôn ngữ, bảo mật truy cập mã, quản lý thời gian sống của đối tượng và hỗ trợ gỡ lỗi
Mã được biên dịch và hướng tới CLR có tên “managed code”. “Managed code” cung cấp siêu dữ liệu (metadata) cần thiết cho CLR để cung cấp các dịch vụ hỗ trợ đa ngôn ngữ, bảo mật mã, quản lý thời gian sống của đối tượng và quản lý bộ nhớ.
Biên dịch mã quản lý (managed code)
.NET Framework đòi hỏi bạn phải sử dụng một trình biên dịch ngôn ngữ “nhắm” vào CLR như trình biên dịch Visual Basic .NET, C# .NET, C++ .NET hay JScript .NET của Microsoft. Chú ý rằng có nhiều trình biên dịch của đối tác thứ ba có trên thị trường như COBOL và Perl.
Sau khi sử dụng một trong các trình biên dịch ngôn ngữ, mã của bạn được biên dịch sang Microsoft Intermediate Language (MSIL hay đơn giản IL). IL là một tập các lệnh độc lập CPU có thể được chuyển đổi dễ dàng sang “native code”. Siêu dữ liệu cũng được chứa bên trong IL.
IL độc lập với CPU có nghĩa mã IL không đáng tin cậy trên máy tính đặc thù sinh ra nó. Nói cách khác, nó có thể được chuyển từ một máy này sang một máy khác (miễn là máy tính hỗ trợ .NET Framework) mà không gặp bất cứ khó khǎn nào. Sau IL, mã mà bạn bắt đầu với nó sẽ được biên dịch bởi trình biên dịch JIT (Just-In-Time) tới mã máy hay “native code”. IL chứa đựng mọi thứ cần thiết để làm điều này như nạp các chỉ lệnh và gọi các hàm (call methods) và một số các thao tác khác.
Trình biên dịch JIT
.NET Framework chứa đựng một hay nhiều trình biên dịch JIT có thể biên dịch mã IL của bạn ra mã máy hay mã cho CPU cụ thể. Điều đó được thực hiện khi ứng dụng chạy lần đầu tiên.
Bạn hãy chú ý quá trình này khi bạn xây dựng trang ASP.NET đầu tiên của mình. Sau khi bạn xây dựng một trang ASP.NET bất kỳ, bạn biên dịch trang này sang IL. Khi sử dụng trình duyệt và gọi trang bằng cách gõ URL của nó vào thanh địa chỉ, bạn chú ý một sự tạm dừng không đáng kể khoảng vài giây. Trên thực tế nó đang gọi mã IL và chuyển nó với một trình biên dịch JIT để để biên dịch sang mã máy. Điều đó chỉ xảy ra lần đầu khi một ai đó yêu cầu trang này. Sau lần đầu, bạn có thể gõ F5 để “refresh” lại trạng này và trang được thực hiện ngay lập tức. Trang đã được chuyển đổi sang mã máy và bây giờ được lưu giữ trong bộ nhớ. CLR biết rằng trình biên dịch JIT đã biên dịch trang. Chính vì thế, nó nhận được đầu ra của trang từ bộ nhớ. Nếu về sau bạn làm một sự thay đổi trang ASP.NET của bạn, hãy biên dịch lại, sau đó chạy trang lần nữa, CLR phát hiện ra có sự thay đổi file gốc. Nó sử dụng trình biên dịch JIT một lần nữa để biên dịch mã IL sang mã máy.
Trình biên dịch JIT đảm bảo, trong quá trình biên dịch sang mã máy, mã được an toàn kiểu (type safe). Điều đó có nghĩa những đối tượng luôn tách rời và chúng không cố ý làm hỏng một đối tượng khác.
Các Assembly
Trong các ứng dụng bạn xây dựng bên trong .NET Framework, các assembly luôn đóng một vai trò quan trọng. Các assembly có thể được hiểu như các khối hợp nhất (building block) của các ứng dụng của bạn. Nếu thiếu một assembly liên quan, mã sẽ không thể biên dịch được từ IL. Khi bạn đang sử dụng trình biên dịch để biên dịch mã từ mã được quản lý (managed code) sang mã máy, trình biên dịch JIT sẽ tìm kiếm mã IL được cất giữ trong một file PE cùng “assembly manifest” (bản kê khai assembly) có liên quan. Cứ mỗi lần bạn tạo một ứng dụng Web Form hay Windows Form trong .NET, thực tế bạn đang tạo ra một assembly. Cứ mỗi ứng dụng trong các ứng dụng này có chứa tối thiểu một assembly.
Trong Windows DNA, nơi các DLL và EXE là những “khối hợp nhất” (building block) của các ứng dụng, trong .NET, nó là assembly được sử dụng như một cơ sở cho các ứng dụng.
Trong Windows DNA và COM, có những trường hợp được tham chiếu đến như DLL hell. Các thành phần COM nói chung được thiết kế để chỉ có một phiên bản của thành phần COM này trên một máy tính tại bất kỳ thời gian đã cho nào. Bởi vì đặc tả COM không bao gồm cả thông tin phụ thuộc trong một định nghĩa kiểu của thành phần. Với .NET, điều đó bây giờ có thể có nhiều phiên bản của các component, hay các assembly, chạy trên cùng một server cạnh nhau. Một ứng dụng sẽ luôn luôn tìm kiếm assembly xây dựng nó.
Khi một ứng dụng được bắt đầu trong .NET, ứng dụng sẽ tìm kiếm một assembly trong thư mục cài đặt. Các assembly được lưu giữ trong một thư mục cài đặt được trỏ đến đến các private assembly. Nếu ứng dụng không tìm ra assembly trong thư mục cài đặt, ứng dụng sẽ quay ra GAC (Global Assembly Cache) để tìm chúng.
Cấu trúc của một assembly:
Các assembly chứa mã được thực hiện bởi Common Language Runtime. Cái được lớn nhất của assembly là chúng “tự mô tả” (self-describing). Tất cả những chi tiết về assembly được cất giữ bên trong bản thân assembly đó. Trong Windows DNA, COM cất giữ tất cả dữ liệu “tự mô tả” của nó trong nơi đăng ký (registry) của server, và như vậy việc cài đặt cũng như loại bỏ các thành phần COM có nghĩa dừng hoạt động (shutting down) IIS. Bởi vì một assembly .NET cất giữ thông tin này bên trong bản thân nó, nó có thể thực hiện chức nǎng XCOPY. Cài đặt một assembly cũng đơn giản như copy nó và điều đó là không cần thiết để dừng hay bắt đầu IIS trong nó đang hoạt động.
Các assembly được tạo ra bởi các phần sau :
Bản kê khai assembly (Assembly manifest)
Kiểu siêu dữ liệu (Type metadata)
Mã MSIL (Microsoft Intermediate Language code)
Assembly manifest là nơi các chi tiết của assembly được cất giữ. Còn assembly được cất giữ bên trong bản thân DLL hay EXE. Các assembly có thể là những file assembly đơn hay nhiều file, và bởi vậy assembly các assembly manifest được cất giữ trong assembly hay trong một file rời. assembly manifest cũng cất giữ số phiên bản của assembly để đảm bảo rằng ứng dụng luôn luôn được sử dụng đúng phiên bản. Khi bạn có nhiều phiên bản của một assembly trên cùng một máy tính, điều đó là rất quan trọng để gán nhãn chúng thật cẩn thận, như vậy CLR biết được phiên bản nào đang được sử dụng.
Các số phiên bản trong các assembly được xây dựng theo các cách sau: Kiểu siêu dữ liệu (Type metadata) đã được hiểu như “dữ liệu về dữ liệu” (data about data). Siêu dữ liệu này chứa thông tin trên những kiểu được đưa ra bởi assembly như thông tin cho phép bảo mật, thông tin về giao diện và lớp và các thông tin về assembly khác.
Garbage collection (gom rác)
.NET Framework là một môi trường “gom rác”. “Gom rác” là quá trình của sự phát hiện khi các đối tượng không còn được sử dụng và tự động phá hủy các đối tượng này, như vậy bộ nhớ được giải phóng.
“Gom rác” không phải là một khái niệm mới. Nó đã được sử dụng trong các ngôn ngữ khác từ khá lâu rồi. Trong thực tế, Java đã có một hệ thống “gom rác” đúng chỗ. Các ngôn ngữ khác như C++ không có “gom rác”. Những nhà phát triển C++ được yêu cầu rất cẩn thận khi hủy bỏ một đối tượng và giải phóng bộ nhớ. Điều đó dẫn đến một số vấn đề thiếu hụt bộ nhớ. Nếu nhà phát triển quên giải phóng các đối tượng từ ứng dụng, việc cấp phát bộ nhớ của ứng dụng ngày càng tǎng, đôi khi là rất đáng kể. Việc giải phóng các đối tượng quá sớm sẽ nảy sinh lỗi ứng dụng; các kiểu lỗi này, trong phần lớn trường hợp, thường rất khó để theo dõi.
Trong .NET, bộ “gom rác” cho phép bạn khi làm việc mà không phải theo dõi mã cho những đối tượng không cần thiết và phá hủy chúng. bộ “gom rác” sẽ chú ý tất cả những điều này cho bạn. “Gom rác” không xảy ra ngay lập tức, nhưng thay vào đó bộ “gom rác” thỉnh thoảng sẽ “vun đống” để xác định những đối tượng nào sẽ phải phá hủy. Hệ thống mới này hoàn toàn miễn trách nhiệm cho người phát triển luôn phải tìm cách để sử dụng cũng như giải phóng bộ nhớ.
Với bộ “gom rác” mới này, bạn có thể điều khiển những khía cạnh nhất định của những hàm của nó, như nó làm việc “sau hậu trường” trong ứng dụng của bạn. Trong SDK documentation, tìm lớp System.GC để có thêm thông tin.
Base Class Libraries
Thư viện các lớp cơ sở .NET Framework cung cấp một tập các lớp (“APIs”), hướng đối tượng, có thứ bậc và có thể mở rộng và chúng được sử dụng bởi bất cứ ngôn ngữ lập trình nào. Như vậy, tất cả các ngôn ngữ từ Jscript cho tới C++ trở nên bình đẳng, và các nhà phát triển có thể tự do lựa chọn ngôn ngữ mà họ vẫn quen dùng.
Tập các lớp, các kiểu giá trị và giao diện này được tổ chức bằng một hệ thống các Namespace (xem định nghĩa phần dưới). Bảng 1 dưới đây đưa ra một mô tả chi tiết những Namespace có sẵn trong .NET Framework. Một điều rất quan trọng là chúng ta không chỉ giới hạn ở các Namespace này. Bạn có thể tự tạo ra Namespace và sử dụng chúng trong ứng dụng của bạn hay cũng có thể sử dụng các Namespace của đối tác thứ ba đang có đầy trên thị trường. Một ví dụ cho trường hợp này là Namespace System.Data.Oracle.